From 6c3d98a3c29a7445298fc3a435dfb72defa75975 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Sun, 22 May 2016 19:49:39 +0530 Subject: [PATCH 001/179] rustfmt--ing files --- src/libcoretest/any.rs | 20 +- src/libcoretest/atomic.rs | 6 +- src/libcoretest/cell.rs | 10 +- src/libcoretest/char.rs | 20 +- src/libcoretest/cmp.rs | 6 +- src/libcoretest/hash/mod.rs | 34 +- src/libcoretest/hash/sip.rs | 175 ++- src/libcoretest/intrinsics.rs | 6 +- src/libcoretest/iter.rs | 144 ++- src/libcoretest/mem.rs | 17 +- src/libcoretest/nonzero.rs | 20 +- src/libcoretest/num/bignum.rs | 82 +- src/libcoretest/num/dec2flt/parse.rs | 16 +- src/libcoretest/num/dec2flt/rawfp.rs | 25 +- src/libcoretest/num/flt2dec/estimator.rs | 4 +- src/libcoretest/num/flt2dec/mod.rs | 1009 ++++++++++------- .../num/flt2dec/strategy/dragon.rs | 1 - src/libcoretest/num/flt2dec/strategy/grisu.rs | 26 +- src/libcoretest/num/mod.rs | 17 +- src/libcoretest/ops.rs | 12 +- src/libcoretest/option.rs | 32 +- src/libcoretest/ptr.rs | 26 +- src/libcoretest/result.rs | 41 +- src/libcoretest/tuple.rs | 2 +- 24 files changed, 995 insertions(+), 756 deletions(-) diff --git a/src/libcoretest/any.rs b/src/libcoretest/any.rs index a9fc8913182b..1ff1d470064a 100644 --- a/src/libcoretest/any.rs +++ b/src/libcoretest/any.rs @@ -35,7 +35,9 @@ fn any_referenced() { #[test] fn any_owning() { - let (a, b, c) = (box 5_usize as Box, box TEST as Box, box Test as Box); + let (a, b, c) = (box 5_usize as Box, + box TEST as Box, + box Test as Box); assert!(a.is::()); assert!(!b.is::()); @@ -56,12 +58,12 @@ fn any_downcast_ref() { match a.downcast_ref::() { Some(&5) => {} - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } match a.downcast_ref::() { None => {} - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } } @@ -79,7 +81,7 @@ fn any_downcast_mut() { assert_eq!(*x, 5); *x = 612; } - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } match b_r.downcast_mut::() { @@ -87,27 +89,27 @@ fn any_downcast_mut() { assert_eq!(*x, 7); *x = 413; } - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } match a_r.downcast_mut::() { None => (), - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } match b_r.downcast_mut::() { None => (), - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } match a_r.downcast_mut::() { Some(&mut 612) => {} - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } match b_r.downcast_mut::() { Some(&mut 413) => {} - x => panic!("Unexpected value {:?}", x) + x => panic!("Unexpected value {:?}", x), } } diff --git a/src/libcoretest/atomic.rs b/src/libcoretest/atomic.rs index b6bb5fddf4a4..d3871b46f246 100644 --- a/src/libcoretest/atomic.rs +++ b/src/libcoretest/atomic.rs @@ -24,8 +24,8 @@ fn bool_() { #[test] fn bool_and() { let a = AtomicBool::new(true); - assert_eq!(a.fetch_and(false, SeqCst),true); - assert_eq!(a.load(SeqCst),false); + assert_eq!(a.fetch_and(false, SeqCst), true); + assert_eq!(a.load(SeqCst), false); } #[test] @@ -72,7 +72,7 @@ fn int_xor() { static S_FALSE: AtomicBool = AtomicBool::new(false); static S_TRUE: AtomicBool = AtomicBool::new(true); -static S_INT: AtomicIsize = AtomicIsize::new(0); +static S_INT: AtomicIsize = AtomicIsize::new(0); static S_UINT: AtomicUsize = AtomicUsize::new(0); #[test] diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index c0b22274ee9d..9c2493c80006 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -214,7 +214,9 @@ fn as_unsafe_cell() { assert_eq!(1, unsafe { *c1.as_unsafe_cell().get() }); let c2: Cell = Cell::new(0); - unsafe { *c2.as_unsafe_cell().get() = 1; } + unsafe { + *c2.as_unsafe_cell().get() = 1; + } assert_eq!(1, c2.get()); let r1: RefCell = RefCell::new(0); @@ -222,7 +224,9 @@ fn as_unsafe_cell() { assert_eq!(1, unsafe { *r1.as_unsafe_cell().get() }); let r2: RefCell = RefCell::new(0); - unsafe { *r2.as_unsafe_cell().get() = 1; } + unsafe { + *r2.as_unsafe_cell().get() = 1; + } assert_eq!(1, *r2.borrow()); } @@ -279,5 +283,3 @@ fn refcell_ref_coercion() { assert_eq!(&*coerced, comp); } } - - diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index e959e71daf73..f5d014fe8018 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -115,12 +115,12 @@ fn test_is_control() { #[test] fn test_is_digit() { - assert!('2'.is_numeric()); - assert!('7'.is_numeric()); - assert!(!'c'.is_numeric()); - assert!(!'i'.is_numeric()); - assert!(!'z'.is_numeric()); - assert!(!'Q'.is_numeric()); + assert!('2'.is_numeric()); + assert!('7'.is_numeric()); + assert!(!'c'.is_numeric()); + assert!(!'i'.is_numeric()); + assert!(!'z'.is_numeric()); + assert!(!'Q'.is_numeric()); } #[test] @@ -158,7 +158,9 @@ fn test_escape_default() { #[test] fn test_escape_unicode() { - fn string(c: char) -> String { c.escape_unicode().collect() } + fn string(c: char) -> String { + c.escape_unicode().collect() + } let s = string('\x00'); assert_eq!(s, "\\u{0}"); @@ -216,8 +218,8 @@ fn test_len_utf16() { fn test_decode_utf16() { fn check(s: &[u16], expected: &[Result]) { let v = char::decode_utf16(s.iter().cloned()) - .map(|r| r.map_err(|e| e.unpaired_surrogate())) - .collect::>(); + .map(|r| r.map_err(|e| e.unpaired_surrogate())) + .collect::>(); assert_eq!(v, expected); } check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]); diff --git a/src/libcoretest/cmp.rs b/src/libcoretest/cmp.rs index 051356cad164..11147639f3bc 100644 --- a/src/libcoretest/cmp.rs +++ b/src/libcoretest/cmp.rs @@ -45,7 +45,7 @@ fn test_ordering_order() { fn test_user_defined_eq() { // Our type. struct SketchyNum { - num : isize + num: isize, } // Our implementation of `PartialEq` to support `==` and `!=`. @@ -57,6 +57,6 @@ fn test_user_defined_eq() { } // Now these binary operators will work when applied! - assert!(SketchyNum {num: 37} == SketchyNum {num: 34}); - assert!(SketchyNum {num: 25} != SketchyNum {num: 57}); + assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 }); + assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 }); } diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 4ea42644ecdf..67621f201a93 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -29,7 +29,9 @@ impl Hasher for MyHasher { self.hash += *byte as u64; } } - fn finish(&self) -> u64 { self.hash } + fn finish(&self) -> u64 { + self.hash + } } @@ -61,15 +63,15 @@ fn test_writer_hasher() { assert_eq!(hash(&'a'), 97); let s: &str = "a"; - assert_eq!(hash(& s), 97 + 0xFF); + assert_eq!(hash(&s), 97 + 0xFF); // FIXME (#18283) Enable test - //let s: Box = box "a"; - //assert_eq!(hasher.hash(& s), 97 + 0xFF); + // let s: Box = box "a"; + // assert_eq!(hasher.hash(& s), 97 + 0xFF); let cs: &[u8] = &[1, 2, 3]; - assert_eq!(hash(& cs), 9); + assert_eq!(hash(&cs), 9); // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let cs: Box<[u8]> = Box::new([1, 2, 3]); - assert_eq!(hash(& cs), 9); + assert_eq!(hash(&cs), 9); // FIXME (#18248) Add tests for hashing Rc and Rc<[T]> @@ -80,13 +82,23 @@ fn test_writer_hasher() { assert_eq!(hash(&ptr), 5); } -struct Custom { hash: u64 } -struct CustomHasher { output: u64 } +struct Custom { + hash: u64, +} +struct CustomHasher { + output: u64, +} impl Hasher for CustomHasher { - fn finish(&self) -> u64 { self.output } - fn write(&mut self, _: &[u8]) { panic!() } - fn write_u64(&mut self, data: u64) { self.output = data; } + fn finish(&self) -> u64 { + self.output + } + fn write(&mut self, _: &[u8]) { + panic!() + } + fn write_u64(&mut self, data: u64) { + self.output = data; + } } impl Default for CustomHasher { diff --git a/src/libcoretest/hash/sip.rs b/src/libcoretest/hash/sip.rs index 9b6cedd25b74..24d11707e41e 100644 --- a/src/libcoretest/hash/sip.rs +++ b/src/libcoretest/hash/sip.rs @@ -66,72 +66,70 @@ fn hash_bytes(x: &[u8]) -> u64 { #[test] #[allow(unused_must_use)] fn test_siphash() { - let vecs : [[u8; 8]; 64] = [ - [ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ], - [ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ], - [ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ], - [ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ], - [ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ], - [ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ], - [ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ], - [ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ], - [ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ], - [ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ], - [ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ], - [ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ], - [ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ], - [ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ], - [ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ], - [ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ], - [ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ], - [ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ], - [ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ], - [ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ], - [ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ], - [ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ], - [ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ], - [ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ], - [ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ], - [ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ], - [ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ], - [ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ], - [ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ], - [ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ], - [ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ], - [ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ], - [ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ], - [ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ], - [ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ], - [ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ], - [ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ], - [ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ], - [ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ], - [ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ], - [ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ], - [ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ], - [ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ], - [ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ], - [ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ], - [ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ], - [ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ], - [ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ], - [ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ], - [ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ], - [ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ], - [ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ], - [ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ], - [ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ], - [ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ], - [ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ], - [ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ], - [ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ], - [ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ], - [ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ], - [ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ], - [ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ], - [ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ], - [ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ] - ]; + let vecs: [[u8; 8]; 64] = [[0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72], + [0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74], + [0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d], + [0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85], + [0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf], + [0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18], + [0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb], + [0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab], + [0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93], + [0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e], + [0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a], + [0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4], + [0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75], + [0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14], + [0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7], + [0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1], + [0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f], + [0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69], + [0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b], + [0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb], + [0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe], + [0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0], + [0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93], + [0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8], + [0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8], + [0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc], + [0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17], + [0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f], + [0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde], + [0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6], + [0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad], + [0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32], + [0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71], + [0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7], + [0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12], + [0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15], + [0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31], + [0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02], + [0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca], + [0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a], + [0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e], + [0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad], + [0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18], + [0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4], + [0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9], + [0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9], + [0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb], + [0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0], + [0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6], + [0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7], + [0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee], + [0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1], + [0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a], + [0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81], + [0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f], + [0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24], + [0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7], + [0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea], + [0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60], + [0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66], + [0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c], + [0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f], + [0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5], + [0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95]]; let k0 = 0x_07_06_05_04_03_02_01_00; let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; @@ -157,19 +155,22 @@ fn test_siphash() { } } -#[test] #[cfg(target_arch = "arm")] +#[test] +#[cfg(target_arch = "arm")] fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; assert!(hash(&(val as u64)) != hash(&(val as usize))); assert_eq!(hash(&(val as u32)), hash(&(val as usize))); } -#[test] #[cfg(target_arch = "x86_64")] +#[test] +#[cfg(target_arch = "x86_64")] fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; assert_eq!(hash(&(val as u64)), hash(&(val as usize))); assert!(hash(&(val as u32)) != hash(&(val as usize))); } -#[test] #[cfg(target_arch = "x86")] +#[test] +#[cfg(target_arch = "x86")] fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; assert!(hash(&(val as u64)) != hash(&(val as usize))); @@ -276,9 +277,7 @@ officia deserunt mollit anim id est laborum."; fn bench_u32(b: &mut Bencher) { let u = 162629500u32; let u = black_box(u); - b.iter(|| { - hash(&u) - }); + b.iter(|| hash(&u)); b.bytes = 8; } @@ -288,9 +287,7 @@ fn bench_u32_keyed(b: &mut Bencher) { let u = black_box(u); let k1 = black_box(0x1); let k2 = black_box(0x2); - b.iter(|| { - hash_with_keys(k1, k2, &u) - }); + b.iter(|| hash_with_keys(k1, k2, &u)); b.bytes = 8; } @@ -298,62 +295,48 @@ fn bench_u32_keyed(b: &mut Bencher) { fn bench_u64(b: &mut Bencher) { let u = 16262950014981195938u64; let u = black_box(u); - b.iter(|| { - hash(&u) - }); + b.iter(|| hash(&u)); b.bytes = 8; } #[bench] fn bench_bytes_4(b: &mut Bencher) { let data = black_box([b' '; 4]); - b.iter(|| { - hash_bytes(&data) - }); + b.iter(|| hash_bytes(&data)); b.bytes = 4; } #[bench] fn bench_bytes_7(b: &mut Bencher) { let data = black_box([b' '; 7]); - b.iter(|| { - hash_bytes(&data) - }); + b.iter(|| hash_bytes(&data)); b.bytes = 7; } #[bench] fn bench_bytes_8(b: &mut Bencher) { let data = black_box([b' '; 8]); - b.iter(|| { - hash_bytes(&data) - }); + b.iter(|| hash_bytes(&data)); b.bytes = 8; } #[bench] fn bench_bytes_a_16(b: &mut Bencher) { let data = black_box([b' '; 16]); - b.iter(|| { - hash_bytes(&data) - }); + b.iter(|| hash_bytes(&data)); b.bytes = 16; } #[bench] fn bench_bytes_b_32(b: &mut Bencher) { let data = black_box([b' '; 32]); - b.iter(|| { - hash_bytes(&data) - }); + b.iter(|| hash_bytes(&data)); b.bytes = 32; } #[bench] fn bench_bytes_c_128(b: &mut Bencher) { let data = black_box([b' '; 128]); - b.iter(|| { - hash_bytes(&data) - }); + b.iter(|| hash_bytes(&data)); b.bytes = 128; } diff --git a/src/libcoretest/intrinsics.rs b/src/libcoretest/intrinsics.rs index 2b380abf63c5..55c14c1d0ea4 100644 --- a/src/libcoretest/intrinsics.rs +++ b/src/libcoretest/intrinsics.rs @@ -12,7 +12,8 @@ use core::any::TypeId; #[test] fn test_typeid_sized_types() { - struct X; struct Y(u32); + struct X; + struct Y(u32); assert_eq!(TypeId::of::(), TypeId::of::()); assert_eq!(TypeId::of::(), TypeId::of::()); @@ -22,7 +23,8 @@ fn test_typeid_sized_types() { #[test] fn test_typeid_unsized_types() { trait Z {} - struct X(str); struct Y(Z + 'static); + struct X(str); + struct Y(Z + 'static); assert_eq!(TypeId::of::(), TypeId::of::()); assert_eq!(TypeId::of::(), TypeId::of::()); diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index 56b10d0b79b4..37884dd26e3e 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -9,7 +9,7 @@ // except according to those terms. use core::iter::*; -use core::{i8, i16, isize}; +use core::{i16, i8, isize}; use core::usize; use test::Bencher; @@ -17,52 +17,52 @@ use test::Bencher; #[test] fn test_lt() { let empty: [isize; 0] = []; - let xs = [1,2,3]; - let ys = [1,2,0]; + let xs = [1, 2, 3]; + let ys = [1, 2, 0]; assert!(!xs.iter().lt(ys.iter())); assert!(!xs.iter().le(ys.iter())); - assert!( xs.iter().gt(ys.iter())); - assert!( xs.iter().ge(ys.iter())); + assert!(xs.iter().gt(ys.iter())); + assert!(xs.iter().ge(ys.iter())); - assert!( ys.iter().lt(xs.iter())); - assert!( ys.iter().le(xs.iter())); + assert!(ys.iter().lt(xs.iter())); + assert!(ys.iter().le(xs.iter())); assert!(!ys.iter().gt(xs.iter())); assert!(!ys.iter().ge(xs.iter())); - assert!( empty.iter().lt(xs.iter())); - assert!( empty.iter().le(xs.iter())); + assert!(empty.iter().lt(xs.iter())); + assert!(empty.iter().le(xs.iter())); assert!(!empty.iter().gt(xs.iter())); assert!(!empty.iter().ge(xs.iter())); // Sequence with NaN let u = [1.0f64, 2.0]; - let v = [0.0f64/0.0, 3.0]; + let v = [0.0f64 / 0.0, 3.0]; assert!(!u.iter().lt(v.iter())); assert!(!u.iter().le(v.iter())); assert!(!u.iter().gt(v.iter())); assert!(!u.iter().ge(v.iter())); - let a = [0.0f64/0.0]; + let a = [0.0f64 / 0.0]; let b = [1.0f64]; let c = [2.0f64]; - assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); + assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); assert!(a.iter().le(b.iter()) == (a[0] <= b[0])); - assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); + assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); assert!(a.iter().ge(b.iter()) == (a[0] >= b[0])); - assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); + assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); assert!(c.iter().le(b.iter()) == (c[0] <= b[0])); - assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); + assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); assert!(c.iter().ge(b.iter()) == (c[0] >= b[0])); } #[test] fn test_multi_iter() { - let xs = [1,2,3,4]; - let ys = [4,3,2,1]; + let xs = [1, 2, 3, 4]; + let ys = [4, 3, 2, 1]; assert!(xs.iter().eq(ys.iter().rev())); assert!(xs.iter().lt(xs.iter().skip(2))); } @@ -148,9 +148,18 @@ fn test_iterator_chain_find() { #[test] fn test_filter_map() { - let it = (0..).step_by(1).take(10) - .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None }); - assert_eq!(it.collect::>(), [0*0, 2*2, 4*4, 6*6, 8*8]); + let it = (0..) + .step_by(1) + .take(10) + .filter_map(|x| { + if x % 2 == 0 { + Some(x * x) + } else { + None + } + }); + assert_eq!(it.collect::>(), + [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]); } #[test] @@ -310,7 +319,7 @@ fn test_iterator_skip() { while let Some(&x) = it.next() { assert_eq!(x, ys[i]); i += 1; - assert_eq!(it.len(), xs.len()-5-i); + assert_eq!(it.len(), xs.len() - 5 - i); } assert_eq!(i, ys.len()); assert_eq!(it.len(), 0); @@ -407,7 +416,7 @@ fn test_iterator_take() { while let Some(&x) = it.next() { assert_eq!(x, ys[i]); i += 1; - assert_eq!(it.len(), 5-i); + assert_eq!(it.len(), 5 - i); } assert_eq!(i, ys.len()); assert_eq!(it.len(), 0); @@ -447,7 +456,7 @@ fn test_iterator_take_short() { while let Some(&x) = it.next() { assert_eq!(x, ys[i]); i += 1; - assert_eq!(it.len(), 4-i); + assert_eq!(it.len(), 4 - i); } assert_eq!(i, ys.len()); assert_eq!(it.len(), 0); @@ -584,9 +593,10 @@ fn test_iterator_size_hint() { assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None)); assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None)); assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None)); - assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None)); + assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), + (usize::MAX, None)); assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10))); - assert_eq!(c.clone().scan(0, |_,_| Some(0)).size_hint(), (0, None)); + assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None)); assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None)); assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None)); assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None)); @@ -600,9 +610,10 @@ fn test_iterator_size_hint() { assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10))); assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13))); assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3))); - assert_eq!(vi.clone().scan(0, |_,_| Some(0)).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), + (0, Some(10))); assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().map(|&i| i+1).size_hint(), (10, Some(10))); + assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10))); assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10))); } @@ -684,8 +695,7 @@ fn test_rev() { let mut it = xs.iter(); it.next(); it.next(); - assert!(it.rev().cloned().collect::>() == - vec![16, 14, 12, 10, 8, 6]); + assert!(it.rev().cloned().collect::>() == vec![16, 14, 12, 10, 8, 6]); } #[test] @@ -758,7 +768,13 @@ fn test_double_ended_filter() { #[test] fn test_double_ended_filter_map() { let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None }); + let mut it = xs.iter().filter_map(|&x| { + if x & 1 == 0 { + Some(x * 2) + } else { + None + } + }); assert_eq!(it.next_back().unwrap(), 12); assert_eq!(it.next_back().unwrap(), 8); assert_eq!(it.next().unwrap(), 4); @@ -783,11 +799,20 @@ fn test_double_ended_chain() { // test that .chain() is well behaved with an unfused iterator struct CrazyIterator(bool); - impl CrazyIterator { fn new() -> CrazyIterator { CrazyIterator(false) } } + impl CrazyIterator { + fn new() -> CrazyIterator { + CrazyIterator(false) + } + } impl Iterator for CrazyIterator { type Item = i32; fn next(&mut self) -> Option { - if self.0 { Some(99) } else { self.0 = true; None } + if self.0 { + Some(99) + } else { + self.0 = true; + None + } } } @@ -803,8 +828,14 @@ fn test_double_ended_chain() { #[test] fn test_rposition() { - fn f(xy: &(isize, char)) -> bool { let (_x, y) = *xy; y == 'b' } - fn g(xy: &(isize, char)) -> bool { let (_x, y) = *xy; y == 'd' } + fn f(xy: &(isize, char)) -> bool { + let (_x, y) = *xy; + y == 'b' + } + fn g(xy: &(isize, char)) -> bool { + let (_x, y) = *xy; + y == 'd' + } let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert_eq!(v.iter().rposition(f), Some(3)); @@ -814,9 +845,7 @@ fn test_rposition() { #[test] #[should_panic] fn test_rposition_panic() { - let v: [(Box<_>, Box<_>); 4] = - [(box 0, box 0), (box 0, box 0), - (box 0, box 0), (box 0, box 0)]; + let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), (box 0, box 0), (box 0, box 0)]; let mut i = 0; v.iter().rposition(|_elt| { if i == 2 { @@ -830,18 +859,18 @@ fn test_rposition_panic() { #[test] fn test_double_ended_flat_map() { - let u = [0,1]; - let v = [5,6,7,8]; + let u = [0, 1]; + let v = [5, 6, 7, 8]; let mut it = u.iter().flat_map(|x| &v[*x..v.len()]); assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.next().unwrap(), &5); assert_eq!(it.next_back().unwrap(), &7); assert_eq!(it.next_back().unwrap(), &6); assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &6); + assert_eq!(it.next().unwrap(), &6); assert_eq!(it.next_back().unwrap(), &7); assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); + assert_eq!(it.next(), None); assert_eq!(it.next_back(), None); } @@ -861,7 +890,8 @@ fn test_double_ended_range() { #[test] fn test_range() { assert_eq!((0..5).collect::>(), [0, 1, 2, 3, 4]); - assert_eq!((-10..-1).collect::>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]); + assert_eq!((-10..-1).collect::>(), + [-10, -9, -8, -7, -6, -5, -4, -3, -2]); assert_eq!((0..5).rev().collect::>(), [4, 3, 2, 1, 0]); assert_eq!((200..-5).count(), 0); assert_eq!((200..-5).rev().count(), 0); @@ -897,18 +927,12 @@ fn test_range_step() { assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0))); assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0))); assert_eq!((0..1).step_by(0).size_hint(), (0, None)); - assert_eq!((i8::MAX..i8::MIN).step_by(i8::MIN).size_hint(), (2, Some(2))); - assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX).size_hint(), (3, Some(3))); - assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_peekable_is_empty() { - let a = [1]; - let mut it = a.iter().peekable(); - assert!( !it.is_empty() ); - it.next(); - assert!( it.is_empty() ); + assert_eq!((i8::MAX..i8::MIN).step_by(i8::MIN).size_hint(), + (2, Some(2))); + assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX).size_hint(), + (3, Some(3))); + assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), + (usize::MAX, Some(usize::MAX))); } #[test] @@ -994,7 +1018,11 @@ fn bench_skip_while(b: &mut Bencher) { b.iter(|| { let it = 0..100; let mut sum = 0; - it.skip_while(|&x| { sum += x; sum < 4000 }).all(|_| true); + it.skip_while(|&x| { + sum += x; + sum < 4000 + }) + .all(|_| true); }); } @@ -1009,7 +1037,9 @@ fn bench_multiple_take(b: &mut Bencher) { }); } -fn scatter(x: i32) -> i32 { (x * 31) % 127 } +fn scatter(x: i32) -> i32 { + (x * 31) % 127 +} #[bench] fn bench_max_by_key(b: &mut Bencher) { diff --git a/src/libcoretest/mem.rs b/src/libcoretest/mem.rs index 5bc08376d257..b3f3d803c180 100644 --- a/src/libcoretest/mem.rs +++ b/src/libcoretest/mem.rs @@ -92,7 +92,8 @@ fn test_transmute_copy() { #[test] fn test_transmute() { - trait Foo { fn dummy(&self) { } } + trait Foo { + fn dummy(&self) {} } impl Foo for isize {} let a = box 100isize as Box; @@ -112,7 +113,7 @@ fn test_transmute() { // Static/dynamic method dispatch struct Struct { - field: isize + field: isize, } trait Trait { @@ -129,17 +130,13 @@ impl Trait for Struct { fn trait_vtable_method_call(b: &mut Bencher) { let s = Struct { field: 10 }; let t = &s as &Trait; - b.iter(|| { - t.method() - }); + b.iter(|| t.method()); } #[bench] fn trait_static_method_call(b: &mut Bencher) { let s = Struct { field: 10 }; - b.iter(|| { - s.method() - }); + b.iter(|| s.method()); } // Overhead of various match forms @@ -150,14 +147,14 @@ fn match_option_some(b: &mut Bencher) { b.iter(|| { match x { Some(y) => y, - None => 11 + None => 11, } }); } #[bench] fn match_vec_pattern(b: &mut Bencher) { - let x = [1,2,3,4,5,6]; + let x = [1, 2, 3, 4, 5, 6]; b.iter(|| { match x { [1,2,3,..] => 10, diff --git a/src/libcoretest/nonzero.rs b/src/libcoretest/nonzero.rs index 7a367ddeec8d..ce86e5aba3ab 100644 --- a/src/libcoretest/nonzero.rs +++ b/src/libcoretest/nonzero.rs @@ -15,9 +15,7 @@ use std::mem::size_of; #[test] fn test_create_nonzero_instance() { - let _a = unsafe { - NonZero::new(21) - }; + let _a = unsafe { NonZero::new(21) }; } #[test] @@ -27,17 +25,15 @@ fn test_size_nonzero_in_option() { #[test] fn test_match_on_nonzero_option() { - let a = Some(unsafe { - NonZero::new(42) - }); + let a = Some(unsafe { NonZero::new(42) }); match a { Some(val) => assert_eq!(*val, 42), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZero(_))"), } match unsafe { Some(NonZero::new(43)) } { Some(val) => assert_eq!(*val, 43), - None => panic!("unexpected None while matching on Some(NonZero(_))") + None => panic!("unexpected None while matching on Some(NonZero(_))"), } } @@ -55,7 +51,7 @@ fn test_match_option_vec() { let a = Some(vec![1, 2, 3, 4]); match a { Some(v) => assert_eq!(v, [1, 2, 3, 4]), - None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])") + None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])"), } } @@ -66,7 +62,7 @@ fn test_match_option_rc() { let five = Rc::new(5); match Some(five) { Some(r) => assert_eq!(*r, 5), - None => panic!("unexpected None while matching on Some(Rc::new(5))") + None => panic!("unexpected None while matching on Some(Rc::new(5))"), } } @@ -77,7 +73,7 @@ fn test_match_option_arc() { let five = Arc::new(5); match Some(five) { Some(a) => assert_eq!(*a, 5), - None => panic!("unexpected None while matching on Some(Arc::new(5))") + None => panic!("unexpected None while matching on Some(Arc::new(5))"), } } @@ -95,6 +91,6 @@ fn test_match_option_string() { let five = "Five".to_string(); match Some(five) { Some(s) => assert_eq!(s, "Five"), - None => panic!("unexpected None while matching on Some(String { ... })") + None => panic!("unexpected None while matching on Some(String { ... })"), } } diff --git a/src/libcoretest/num/bignum.rs b/src/libcoretest/num/bignum.rs index 58a9dd1b128c..e05396693c75 100644 --- a/src/libcoretest/num/bignum.rs +++ b/src/libcoretest/num/bignum.rs @@ -19,12 +19,18 @@ fn test_from_u64_overflow() { #[test] fn test_add() { - assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7)); - assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3)); - assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3)); - assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001)); - assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665)); - assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665)); + assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), + Big::from_small(7)); + assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), + Big::from_small(3)); + assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), + Big::from_small(3)); + assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), + Big::from_u64(0x10001)); + assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), + Big::from_u64(0x10665)); + assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), + Big::from_u64(0x10665)); } #[test] @@ -46,7 +52,8 @@ fn test_add_small() { assert_eq!(*Big::from_small(0).add_small(3), Big::from_small(3)); assert_eq!(*Big::from_small(7).add_small(250), Big::from_u64(257)); assert_eq!(*Big::from_u64(0x7fff).add_small(1), Big::from_u64(0x8000)); - assert_eq!(*Big::from_u64(0x2ffe).add_small(0x35), Big::from_u64(0x3033)); + assert_eq!(*Big::from_u64(0x2ffe).add_small(0x35), + Big::from_u64(0x3033)); assert_eq!(*Big::from_small(0xdc).add_small(0x89), Big::from_u64(0x165)); } @@ -58,11 +65,16 @@ fn test_add_small_overflow() { #[test] fn test_sub() { - assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0)); + assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), + Big::from_small(3)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), + Big::from_u64(0xfedc)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), + Big::from_u64(0x789)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), + Big::from_small(1)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), + Big::from_small(0)); } #[test] @@ -80,8 +92,10 @@ fn test_sub_underflow_2() { #[test] fn test_mul_small() { assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35)); - assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01)); - assert_eq!(*Big::from_u64(0xffffff/13).mul_small(13), Big::from_u64(0xffffff)); + assert_eq!(*Big::from_small(0xff).mul_small(0xff), + Big::from_u64(0xfe01)); + assert_eq!(*Big::from_u64(0xffffff / 13).mul_small(13), + Big::from_u64(0xffffff)); } #[test] @@ -141,12 +155,18 @@ fn test_mul_pow5_overflow_2() { #[test] fn test_mul_digits() { assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15)); - assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01)); - assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2)); - assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3)); - assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e)); - assert_eq!(*Big::from_u64(0xffffff/13).mul_digits(&[13]), Big::from_u64(0xffffff)); - assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff)); + assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), + Big::from_u64(0xfe01)); + assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), + Big::from_u64(0x4edc2)); + assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), + Big::from_u64(0x7530c3)); + assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), + Big::from_u64(0x3ae13e)); + assert_eq!(*Big::from_u64(0xffffff / 13).mul_digits(&[13]), + Big::from_u64(0xffffff)); + assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), + Big::from_u64(0xffffff)); } #[test] @@ -164,9 +184,12 @@ fn test_mul_digits_overflow_2() { #[test] fn test_div_rem_small() { let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r); - assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0)); - assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15)); - assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3)); + assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), + (Big::from_small(17), 0)); + assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), + (Big::from_small(15), 15)); + assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), + (Big::from_small(0), 3)); assert_eq!(as_val(Big::from_u64(0xffffff).div_rem_small(123)), (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8)); assert_eq!(as_val(Big::from_u64(0x10000).div_rem_small(123)), @@ -186,10 +209,14 @@ fn test_div_rem() { assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1))); assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0))); assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4))); - assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25))); - assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0))); - assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee))); - assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0))); + assert_eq!(div_rem(123456, 77), + (Big::from_u64(1603), Big::from_small(25))); + assert_eq!(div_rem(0xffff, 1), + (Big::from_u64(0xffff), Big::from_small(0))); + assert_eq!(div_rem(0xeeee, 0xffff), + (Big::from_small(0), Big::from_u64(0xeeee))); + assert_eq!(div_rem(2_000_000, 2), + (Big::from_u64(1_000_000), Big::from_u64(0))); } #[test] @@ -246,4 +273,3 @@ fn test_fmt() { assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45"); assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56"); } - diff --git a/src/libcoretest/num/dec2flt/parse.rs b/src/libcoretest/num/dec2flt/parse.rs index 09acf2bc517b..e56a03ea5892 100644 --- a/src/libcoretest/num/dec2flt/parse.rs +++ b/src/libcoretest/num/dec2flt/parse.rs @@ -30,7 +30,9 @@ fn invalid_chars() { let mut input = String::new(); input.push_str(s); input.insert(i, c); - assert!(parse_decimal(&input) == Invalid, "did not reject invalid {:?}", input); + assert!(parse_decimal(&input) == Invalid, + "did not reject invalid {:?}", + input); } } } @@ -38,14 +40,18 @@ fn invalid_chars() { #[test] fn valid() { - assert_eq!(parse_decimal("123.456e789"), Valid(Decimal::new(b"123", b"456", 789))); - assert_eq!(parse_decimal("123.456e+789"), Valid(Decimal::new(b"123", b"456", 789))); - assert_eq!(parse_decimal("123.456e-789"), Valid(Decimal::new(b"123", b"456", -789))); + assert_eq!(parse_decimal("123.456e789"), + Valid(Decimal::new(b"123", b"456", 789))); + assert_eq!(parse_decimal("123.456e+789"), + Valid(Decimal::new(b"123", b"456", 789))); + assert_eq!(parse_decimal("123.456e-789"), + Valid(Decimal::new(b"123", b"456", -789))); assert_eq!(parse_decimal(".050"), Valid(Decimal::new(b"", b"050", 0))); assert_eq!(parse_decimal("999"), Valid(Decimal::new(b"999", b"", 0))); assert_eq!(parse_decimal("1.e300"), Valid(Decimal::new(b"1", b"", 300))); assert_eq!(parse_decimal(".1e300"), Valid(Decimal::new(b"", b"1", 300))); - assert_eq!(parse_decimal("101e-33"), Valid(Decimal::new(b"101", b"", -33))); + assert_eq!(parse_decimal("101e-33"), + Valid(Decimal::new(b"101", b"", -33))); let zeros: String = iter::repeat('0').take(25).collect(); let s = format!("1.5e{}", zeros); assert_eq!(parse_decimal(&s), Valid(Decimal::new(b"1", b"5", 0))); diff --git a/src/libcoretest/num/dec2flt/rawfp.rs b/src/libcoretest/num/dec2flt/rawfp.rs index 4c0a403e574a..33fd2c0f4b55 100644 --- a/src/libcoretest/num/dec2flt/rawfp.rs +++ b/src/libcoretest/num/dec2flt/rawfp.rs @@ -53,27 +53,40 @@ fn fp_to_float_half_to_even() { fn integers_to_f64() { assert_eq!(fp_to_float::(Fp { f: 1, e: 0 }), 1.0); assert_eq!(fp_to_float::(Fp { f: 42, e: 7 }), (42 << 7) as f64); - assert_eq!(fp_to_float::(Fp { f: 1 << 20, e: 30 }), (1u64 << 50) as f64); + assert_eq!(fp_to_float::(Fp { + f: 1 << 20, + e: 30, + }), + (1u64 << 50) as f64); assert_eq!(fp_to_float::(Fp { f: 4, e: -3 }), 0.5); } -const SOME_FLOATS: [f64; 9] = - [0.1f64, 33.568, 42.1e-5, 777.0e9, 1.1111, 0.347997, - 9843579834.35892, 12456.0e-150, 54389573.0e-150]; +const SOME_FLOATS: [f64; 9] = [0.1f64, + 33.568, + 42.1e-5, + 777.0e9, + 1.1111, + 0.347997, + 9843579834.35892, + 12456.0e-150, + 54389573.0e-150]; #[test] fn human_f64_roundtrip() { for &x in &SOME_FLOATS { let (f, e, _) = x.integer_decode(); - let fp = Fp { f: f, e: e}; + let fp = Fp { f: f, e: e }; assert_eq!(fp_to_float::(fp), x); } } #[test] fn rounding_overflow() { - let x = Fp { f: 0xFF_FF_FF_FF_FF_FF_FF_00u64, e: 42 }; + let x = Fp { + f: 0xFF_FF_FF_FF_FF_FF_FF_00u64, + e: 42, + }; let rounded = round_normal::(x); let adjusted_k = x.e + 64 - 53; assert_eq!(rounded.sig, 1 << 52); diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcoretest/num/flt2dec/estimator.rs index 21260c520f62..3bed4143cf35 100644 --- a/src/libcoretest/num/flt2dec/estimator.rs +++ b/src/libcoretest/num/flt2dec/estimator.rs @@ -39,7 +39,8 @@ fn test_estimate_scaling_factor() { assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000, -20), -5); assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000 + 1, -20), -4); assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000, -20), -4); - assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000 + 1, -20), -3); + assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000 + 1, -20), + -3); assert_almost_eq!(estimate_scaling_factor(1048575, -20), 0); assert_almost_eq!(estimate_scaling_factor(1048576, -20), 0); assert_almost_eq!(estimate_scaling_factor(1048577, -20), 1); @@ -58,4 +59,3 @@ fn test_estimate_scaling_factor() { assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); } } - diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcoretest/num/flt2dec/mod.rs index 1a592f3ad424..9aad741707ee 100644 --- a/src/libcoretest/num/flt2dec/mod.rs +++ b/src/libcoretest/num/flt2dec/mod.rs @@ -16,8 +16,8 @@ use rand::distributions::{IndependentSample, Range}; use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; use core::num::flt2dec::{MAX_SIG_DIGITS, round_up, Part, Formatted, Sign}; -use core::num::flt2dec::{to_shortest_str, to_shortest_exp_str, - to_exact_exp_str, to_exact_fixed_str}; +use core::num::flt2dec::{to_shortest_str, to_shortest_exp_str, to_exact_exp_str, + to_exact_fixed_str}; pub use test::Bencher; @@ -30,7 +30,7 @@ mod strategy { pub fn decode_finite(v: T) -> Decoded { match decode(v).1 { FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {:?} instead", full_decoded) + full_decoded => panic!("expected finite, got {:?} instead", full_decoded), } } @@ -90,7 +90,9 @@ macro_rules! try_fixed { } fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16) - where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + where T: DecodableFloat, + F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) +{ // use a large enough buffer let mut buf = [b'_'; 1024]; let mut expected_ = [b'_'; 1024]; @@ -105,14 +107,15 @@ fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16 if expected[i] >= b'5' { // check if this is a rounding-to-even case. // we avoid rounding ...x5000... (with infinite zeroes) to ...(x+1) when x is even. - if !(i+1 < expected.len() && expected[i-1] & 1 == 0 && - expected[i] == b'5' && - expected[i+1] == b' ') { + if !(i + 1 < expected.len() && expected[i - 1] & 1 == 0 && expected[i] == b'5' && + expected[i + 1] == b' ') { // if this returns true, expected_[..i] is all `9`s and being rounded up. // we should always return `100..00` (`i` digits) instead, since that's // what we can came up with `i` digits anyway. `round_up` assumes that // the adjustment to the length is done by caller, which we simply ignore. - if let Some(_) = round_up(&mut expected_, i) { expectedk_ += 1; } + if let Some(_) = round_up(&mut expected_, i) { + expectedk_ += 1; + } } } @@ -146,9 +149,11 @@ fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16 // check infinite zero digits if let Some(cut) = cut { - for i in cut..expected.len()-1 { + for i in cut..expected.len() - 1 { expected_[..cut].copy_from_slice(&expected[..cut]); - for c in &mut expected_[cut..i] { *c = b'0'; } + for c in &mut expected_[cut..i] { + *c = b'0'; + } try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk; "exact infzero mismatch for v={v}, i={i}: \ @@ -169,16 +174,21 @@ trait TestableFloat : DecodableFloat + fmt::Display { } impl TestableFloat for f32 { - fn ldexpi(f: i64, exp: isize) -> Self { f as Self * (exp as Self).exp2() } + fn ldexpi(f: i64, exp: isize) -> Self { + f as Self * (exp as Self).exp2() + } } impl TestableFloat for f64 { - fn ldexpi(f: i64, exp: isize) -> Self { f as Self * (exp as Self).exp2() } + fn ldexpi(f: i64, exp: isize) -> Self { + f as Self * (exp as Self).exp2() + } } fn check_exact_one(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16) - where T: TestableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + where T: TestableFloat, + F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) +{ // use a large enough buffer let mut buf = [b'_'; 1024]; let v: T = TestableFloat::ldexpi(x, e); @@ -212,7 +222,9 @@ macro_rules! check_exact_one { // [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion // ftp://ftp.ee.lbl.gov/testbase-report.ps.Z -pub fn f32_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { +pub fn f32_shortest_sanity_test(mut f: F) + where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ // 0.0999999940395355224609375 // 0.100000001490116119384765625 // 0.10000000894069671630859375 @@ -257,7 +269,8 @@ pub fn f32_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) } pub fn f32_exact_sanity_test(mut f: F) - where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) +{ let minf32 = f32::ldexp(1.0, -149); check_exact!(f(0.1f32) => b"100000001490116119384765625 ", 0); @@ -298,7 +311,9 @@ pub fn f32_exact_sanity_test(mut f: F) check_exact_one!(f(13248074, 95; f32) => b"524810279937", 36); } -pub fn f64_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { +pub fn f64_shortest_sanity_test(mut f: F) + where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ // 0.0999999999999999777955395074968691915273... // 0.1000000000000000055511151231257827021181... // 0.1000000000000000333066907387546962127089... @@ -362,7 +377,8 @@ pub fn f64_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) } pub fn f64_exact_sanity_test(mut f: F) - where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) +{ let minf64 = f64::ldexp(1.0, -1074); check_exact!(f(0.1f64) => b"1000000000000000055511151231257827021181", 0); @@ -446,7 +462,9 @@ pub fn f64_exact_sanity_test(mut f: F) check_exact_one!(f(8549497411294502, -448; f64) => b"1176257830728540379990", -118); } -pub fn more_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { +pub fn more_shortest_sanity_test(mut f: F) + where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, exp: 0, inclusive: true} => b"1", 18); check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, @@ -454,9 +472,10 @@ pub fn more_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8] } fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), - V: FnMut(usize) -> Decoded { + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + V: FnMut(usize) -> Decoded +{ assert!(k <= 1024); let mut npassed = 0; // f(x) = Some(g(x)) @@ -465,7 +484,11 @@ fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V for i in 0..n { if (i & 0xfffff) == 0 { println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", - i, n, nignored, npassed, i - nignored - npassed); + i, + n, + nignored, + npassed, + i - nignored - npassed); } let decoded = v(i); @@ -477,48 +500,63 @@ fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V npassed += 1; } else { println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", - i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, - str::from_utf8(&buf2[..len2]).unwrap(), e2); + i, + n, + decoded, + str::from_utf8(&buf1[..len1]).unwrap(), + e1, + str::from_utf8(&buf2[..len2]).unwrap(), + e2); } } else { nignored += 1; } } println!("{}({}): done, ignored={} passed={} failed={}", - func, k, nignored, npassed, n - nignored - npassed); + func, + k, + nignored, + npassed, + n - nignored - npassed); assert!(nignored + npassed == n, "{}({}): {} out of {} values returns an incorrect value!", - func, k, n - nignored - npassed, n); + func, + k, + n - nignored - npassed, + n); (npassed, nignored) } pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); iterate("f32_random_equivalence_test", k, n, f, g, |_| { let i: u32 = f32_range.ind_sample(&mut rng); - let x: f32 = unsafe {mem::transmute(i)}; + let x: f32 = unsafe { mem::transmute(i) }; decode_finite(x) }); } pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); iterate("f64_random_equivalence_test", k, n, f, g, |_| { let i: u64 = f64_range.ind_sample(&mut rng); - let x: f64 = unsafe {mem::transmute(i)}; + let x: f64 = unsafe { mem::transmute(i) }; decode_finite(x) }); } pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, // so why not simply testing all of them? // @@ -527,15 +565,20 @@ pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", - k, 0x7f7f_ffff, f, g, |i: usize| { - let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; - decode_finite(x) - }); + k, + 0x7f7f_ffff, + f, + g, + |i: usize| { + let x: f32 = unsafe { mem::transmute(i as u32 + 1) }; + decode_finite(x) + }); assert_eq!((npassed, nignored), (2121451881, 17643158)); } fn to_string_with_parts(mut f: F) -> String - where F: for<'a> FnMut(&'a mut [u8], &'a mut [Part<'a>]) -> Formatted<'a> { + where F: for<'a> FnMut(&'a mut [u8], &'a mut [Part<'a>]) -> Formatted<'a> +{ let mut buf = [0; 1024]; let mut parts = [Part::Zero(0); 16]; let formatted = f(&mut buf, &mut parts); @@ -545,81 +588,94 @@ fn to_string_with_parts(mut f: F) -> String } pub fn to_shortest_str_test(mut f_: F) - where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize, upper: bool) -> String - where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - to_string_with_parts(|buf, parts| to_shortest_str(|d,b| f(d,b), v, sign, - frac_digits, upper, buf, parts)) + where T: DecodableFloat, + F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) + { + to_string_with_parts(|buf, parts| { + to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, upper, buf, parts) + }) } let f = &mut f_; - assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0, false), "-0"); - assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); - - assert_eq!(to_string(f, 1.0/0.0, Minus, 0, false), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusRaw, 0, true), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlus, 0, false), "+inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, 0, true), "+inf"); - assert_eq!(to_string(f, 0.0/0.0, Minus, 0, false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusRaw, 1, true), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, 64, true), "NaN"); - assert_eq!(to_string(f, -1.0/0.0, Minus, 0, false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusRaw, 1, true), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlus, 8, false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, 64, true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 0, false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3.14"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3.14"); - assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3.14"); + assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0, false), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 0, true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0, false), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 0, true), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0, false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64, true), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0, false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8, false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64, true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0, false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3.14"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3.14"); + assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3.14"); assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0, false), "-3.14"); - assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); - assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); - - assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000000000075"); + assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); + + assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000000000075"); assert_eq!(to_string(f, 7.5e-11, Minus, 12, false), "0.000000000075"); assert_eq!(to_string(f, 7.5e-11, Minus, 13, false), "0.0000000000750"); - assert_eq!(to_string(f, 1.9971e20, Minus, 0, false), "199710000000000000000"); - assert_eq!(to_string(f, 1.9971e20, Minus, 1, false), "199710000000000000000.0"); - assert_eq!(to_string(f, 1.9971e20, Minus, 8, false), "199710000000000000000.00000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, 0, false), + "199710000000000000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, 1, false), + "199710000000000000000.0"); + assert_eq!(to_string(f, 1.9971e20, Minus, 8, false), + "199710000000000000000.00000000"); - assert_eq!(to_string(f, f32::MAX, Minus, 0, false), format!("34028235{:0>31}", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 1, false), format!("34028235{:0>31}.0", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 8, false), format!("34028235{:0>31}.00000000", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 0, false), + format!("34028235{:0>31}", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 1, false), + format!("34028235{:0>31}.0", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 8, false), + format!("34028235{:0>31}.00000000", "")); let minf32 = f32::ldexp(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 0, false), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 45, false), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 46, false), format!("0.{:0>44}10", "")); + assert_eq!(to_string(f, minf32, Minus, 0, false), + format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 45, false), + format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 46, false), + format!("0.{:0>44}10", "")); assert_eq!(to_string(f, f64::MAX, Minus, 0, false), format!("17976931348623157{:0>292}", "")); @@ -629,113 +685,130 @@ pub fn to_shortest_str_test(mut f_: F) format!("17976931348623157{:0>292}.00000000", "")); let minf64 = f64::ldexp(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 0, false), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 324, false), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 325, false), format!("0.{:0>323}50", "")); + assert_eq!(to_string(f, minf64, Minus, 0, false), + format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 324, false), + format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 325, false), + format!("0.{:0>323}50", "")); // very large output - assert_eq!(to_string(f, 1.1, Minus, 80000, false), format!("1.1{:0>79999}", "")); + assert_eq!(to_string(f, 1.1, Minus, 80000, false), + format!("1.1{:0>79999}", "")); } pub fn to_shortest_exp_str_test(mut f_: F) - where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) +{ use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String - where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - to_string_with_parts(|buf, parts| to_shortest_exp_str(|d,b| f(d,b), v, sign, - exp_bounds, upper, buf, parts)) + where T: DecodableFloat, + F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) + { + to_string_with_parts(|buf, parts| { + to_shortest_exp_str(|d, b| f(d, b), v, sign, exp_bounds, upper, buf, parts) + }) } let f = &mut f_; - assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, (-4, 16), false), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, (-4, 16), false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, (-4, 16), false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "+0"); + assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, (-4, 16), false), "+0"); + assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, (-4, 16), false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "+0"); assert_eq!(to_string(f, -0.0, MinusPlusRaw, (-4, 16), false), "-0"); - assert_eq!(to_string(f, 0.0, Minus, ( 0, 0), true), "0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, ( 0, 0), false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, (-9, -5), true), "+0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, ( 5, 9), false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, ( 0, 0), true), "0E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, ( 0, 0), false), "-0e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (-9, -5), true), "+0E0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, ( 5, 9), false), "-0e0"); - - assert_eq!(to_string(f, 1.0/0.0, Minus, (-4, 16), false), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusRaw, (-4, 16), true), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlus, (-4, 16), false), "+inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, (-4, 16), true), "+inf"); - assert_eq!(to_string(f, 0.0/0.0, Minus, ( 0, 0), false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusRaw, ( 0, 0), true), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlus, (-9, -5), false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, ( 5, 9), true), "NaN"); - assert_eq!(to_string(f, -1.0/0.0, Minus, ( 0, 0), false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusRaw, ( 0, 0), true), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlus, (-9, -5), false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, ( 5, 9), true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, (-4, 16), false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, (-4, 16), false), "+3.14"); - assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusRaw, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, 0.0, Minus, (0, 0), true), "0E0"); + assert_eq!(to_string(f, 0.0, MinusRaw, (0, 0), false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (-9, -5), true), "+0E0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, (5, 9), false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "0E0"); + assert_eq!(to_string(f, -0.0, MinusRaw, (0, 0), false), "-0e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (-9, -5), true), "+0E0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, (5, 9), false), "-0e0"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), false), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, (-4, 16), true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), false), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, (-4, 16), true), + "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, (0, 0), true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (-9, -5), false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, (5, 9), true), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, (0, 0), true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (-9, -5), false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, (5, 9), true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, (-4, 16), false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, (-4, 16), false), "+3.14"); + assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusRaw, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); assert_eq!(to_string(f, -3.14, MinusPlusRaw, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, 3.14, Minus, ( 0, 0), true), "3.14E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, ( 0, 0), false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, (-9, -5), true), "+3.14E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, ( 5, 9), false), "+3.14e0"); - assert_eq!(to_string(f, -3.14, Minus, ( 0, 0), true), "-3.14E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, ( 0, 0), false), "-3.14e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, (-9, -5), true), "-3.14E0"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, ( 5, 9), false), "-3.14e0"); - - assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); - assert_eq!(to_string(f, 0.1, MinusRaw, (-4, 16), false), "0.1"); - assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); - assert_eq!(to_string(f, 0.1, MinusPlusRaw, (-4, 16), false), "+0.1"); - assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, -0.1, MinusRaw, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, 3.14, Minus, (0, 0), true), "3.14E0"); + assert_eq!(to_string(f, 3.14, MinusRaw, (0, 0), false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, (-9, -5), true), "+3.14E0"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, (5, 9), false), "+3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, (0, 0), true), "-3.14E0"); + assert_eq!(to_string(f, -3.14, MinusRaw, (0, 0), false), "-3.14e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, (-9, -5), true), "-3.14E0"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, (5, 9), false), "-3.14e0"); + + assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, MinusRaw, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); + assert_eq!(to_string(f, 0.1, MinusPlusRaw, (-4, 16), false), "+0.1"); + assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, -0.1, MinusRaw, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); assert_eq!(to_string(f, -0.1, MinusPlusRaw, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, 0.1, Minus, ( 0, 0), true), "1E-1"); - assert_eq!(to_string(f, 0.1, MinusRaw, ( 0, 0), false), "1e-1"); - assert_eq!(to_string(f, 0.1, MinusPlus, (-9, -5), true), "+1E-1"); - assert_eq!(to_string(f, 0.1, MinusPlusRaw, ( 5, 9), false), "+1e-1"); - assert_eq!(to_string(f, -0.1, Minus, ( 0, 0), true), "-1E-1"); - assert_eq!(to_string(f, -0.1, MinusRaw, ( 0, 0), false), "-1e-1"); - assert_eq!(to_string(f, -0.1, MinusPlus, (-9, -5), true), "-1E-1"); - assert_eq!(to_string(f, -0.1, MinusPlusRaw, ( 5, 9), false), "-1e-1"); - - assert_eq!(to_string(f, 7.5e-11, Minus, ( -4, 16), false), "7.5e-11"); - assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075"); + assert_eq!(to_string(f, 0.1, Minus, (0, 0), true), "1E-1"); + assert_eq!(to_string(f, 0.1, MinusRaw, (0, 0), false), "1e-1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (-9, -5), true), "+1E-1"); + assert_eq!(to_string(f, 0.1, MinusPlusRaw, (5, 9), false), "+1e-1"); + assert_eq!(to_string(f, -0.1, Minus, (0, 0), true), "-1E-1"); + assert_eq!(to_string(f, -0.1, MinusRaw, (0, 0), false), "-1e-1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (-9, -5), true), "-1E-1"); + assert_eq!(to_string(f, -0.1, MinusPlusRaw, (5, 9), false), "-1e-1"); + + assert_eq!(to_string(f, 7.5e-11, Minus, (-4, 16), false), "7.5e-11"); + assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), + "0.000000000075"); assert_eq!(to_string(f, 7.5e-11, Minus, (-10, 11), false), "7.5e-11"); - assert_eq!(to_string(f, 1.9971e20, Minus, ( -4, 16), false), "1.9971e20"); - assert_eq!(to_string(f, 1.9971e20, Minus, (-20, 21), false), "199710000000000000000"); - assert_eq!(to_string(f, 1.9971e20, Minus, (-21, 20), false), "1.9971e20"); + assert_eq!(to_string(f, 1.9971e20, Minus, (-4, 16), false), "1.9971e20"); + assert_eq!(to_string(f, 1.9971e20, Minus, (-20, 21), false), + "199710000000000000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, (-21, 20), false), + "1.9971e20"); // the true value of 1.0e23f64 is less than 10^23, but that shouldn't matter here assert_eq!(to_string(f, 1.0e23, Minus, (22, 23), false), "1e23"); - assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000"); + assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), + "100000000000000000000000"); assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23"); - assert_eq!(to_string(f, f32::MAX, Minus, ( -4, 16), false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", "")); + assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), + "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), + "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), + format!("34028235{:0>31}", "")); let minf32 = f32::ldexp(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, ( -4, 16), false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45"); assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45"); - assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), + format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, f64::MAX, Minus, ( -4, 16), false), + assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308"); assert_eq!(to_string(f, f64::MAX, Minus, (-308, 309), false), format!("17976931348623157{:0>292}", "")); @@ -743,119 +816,145 @@ pub fn to_shortest_exp_str_test(mut f_: F) "1.7976931348623157e308"); let minf64 = f64::ldexp(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, ( -4, 16), false), "5e-324"); - assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324"); + assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), + format!("0.{:0>323}5", "")); assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324"); assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1"); } pub fn to_exact_exp_str_test(mut f_: F) - where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) +{ use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String - where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { - to_string_with_parts(|buf, parts| to_exact_exp_str(|d,b,l| f(d,b,l), v, sign, - ndigits, upper, buf, parts)) + where T: DecodableFloat, + F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) + { + to_string_with_parts(|buf, parts| { + to_exact_exp_str(|d, b, l| f(d, b, l), v, sign, ndigits, upper, buf, parts) + }) } let f = &mut f_; - assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1, false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, 1, true), "0E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 1, false), "-0e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 1, true), "+0E0"); + assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1, false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0E0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, 1, true), "0E0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 1, false), "-0e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 1, true), "+0E0"); assert_eq!(to_string(f, -0.0, MinusPlusRaw, 1, false), "-0e0"); - assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 2, false), "0.0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 2, true), "+0.0E0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 2, false), "+0.0e0"); - assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.0000000E0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8, false), "-0.0000000e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.0000000E0"); + assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 2, false), "0.0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 2, true), "+0.0E0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 2, false), "+0.0e0"); + assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.0000000E0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8, false), "-0.0000000e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.0000000E0"); assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, false), "-0.0000000e0"); - assert_eq!(to_string(f, 1.0/0.0, Minus, 1, false), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusRaw, 1, true), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlus, 1, false), "+inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, 1, true), "+inf"); - assert_eq!(to_string(f, 0.0/0.0, Minus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusRaw, 8, true), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, 8, true), "NaN"); - assert_eq!(to_string(f, -1.0/0.0, Minus, 64, false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusRaw, 64, true), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlus, 64, false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, 64, true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, 1, false), "3e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 1, true), "+3E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 1, false), "+3e0"); - assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, 2, false), "-3.1e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 2, true), "-3.1E0"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, false), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1, true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, false), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 1, true), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 8, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 8, true), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 64, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64, true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); + assert_eq!(to_string(f, 3.14, MinusRaw, 1, false), "3e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 1, true), "+3E0"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 1, false), "+3e0"); + assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); + assert_eq!(to_string(f, -3.14, MinusRaw, 2, false), "-3.1e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 2, true), "-3.1E0"); assert_eq!(to_string(f, -3.14, MinusPlusRaw, 2, false), "-3.1e0"); - assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); - assert_eq!(to_string(f, 3.14, MinusRaw, 3, false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.14E0"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 3, false), "+3.14e0"); - assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); - assert_eq!(to_string(f, -3.14, MinusRaw, 4, false), "-3.140e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 4, true), "-3.140E0"); + assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); + assert_eq!(to_string(f, 3.14, MinusRaw, 3, false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.14E0"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 3, false), "+3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); + assert_eq!(to_string(f, -3.14, MinusRaw, 4, false), "-3.140e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 4, true), "-3.140E0"); assert_eq!(to_string(f, -3.14, MinusPlusRaw, 4, false), "-3.140e0"); - assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); - assert_eq!(to_string(f, 0.195, MinusRaw, 1, true), "2E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 1, false), "+2e-1"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 1, true), "+2E-1"); - assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); - assert_eq!(to_string(f, -0.195, MinusRaw, 2, true), "-2.0E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 2, false), "-2.0e-1"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 2, true), "-2.0E-1"); - assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); - assert_eq!(to_string(f, 0.195, MinusRaw, 3, true), "1.95E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3, false), "+1.95e-1"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 3, true), "+1.95E-1"); - assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); - assert_eq!(to_string(f, -0.195, MinusRaw, 4, true), "-1.950E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 4, false), "-1.950e-1"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 4, true), "-1.950E-1"); - - assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); - assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); - assert_eq!(to_string(f, 9.5, Minus, 3, false), "9.50e0"); - assert_eq!(to_string(f, 9.5, Minus, 30, false), "9.50000000000000000000000000000e0"); - - assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "1e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 2, false), "1.0e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 15, false), "1.00000000000000e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 16, false), "1.000000000000000e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 17, false), "1.0000000000000001e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 18, false), "1.00000000000000009e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 19, false), "1.000000000000000091e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 20, false), "1.0000000000000000906e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 21, false), "1.00000000000000009060e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 22, false), "1.000000000000000090597e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 23, false), "1.0000000000000000905970e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 24, false), "1.00000000000000009059697e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 25, false), "1.000000000000000090596966e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 26, false), "1.0000000000000000905969664e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 27, false), "1.00000000000000009059696640e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 30, false), "1.00000000000000009059696640000e25"); - - assert_eq!(to_string(f, 1.0e-6, Minus, 1, false), "1e-6"); - assert_eq!(to_string(f, 1.0e-6, Minus, 2, false), "1.0e-6"); - assert_eq!(to_string(f, 1.0e-6, Minus, 16, false), "1.000000000000000e-6"); - assert_eq!(to_string(f, 1.0e-6, Minus, 17, false), "9.9999999999999995e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 18, false), "9.99999999999999955e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 19, false), "9.999999999999999547e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 20, false), "9.9999999999999995475e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 30, false), "9.99999999999999954748111825886e-7"); + assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); + assert_eq!(to_string(f, 0.195, MinusRaw, 1, true), "2E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 1, false), "+2e-1"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 1, true), "+2E-1"); + assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); + assert_eq!(to_string(f, -0.195, MinusRaw, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 2, false), "-2.0e-1"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); + assert_eq!(to_string(f, 0.195, MinusRaw, 3, true), "1.95E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3, false), "+1.95e-1"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 3, true), "+1.95E-1"); + assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); + assert_eq!(to_string(f, -0.195, MinusRaw, 4, true), "-1.950E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 4, false), "-1.950e-1"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 4, true), "-1.950E-1"); + + assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); + assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); + assert_eq!(to_string(f, 9.5, Minus, 3, false), "9.50e0"); + assert_eq!(to_string(f, 9.5, Minus, 30, false), + "9.50000000000000000000000000000e0"); + + assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "1e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 2, false), "1.0e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 15, false), + "1.00000000000000e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 16, false), + "1.000000000000000e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 17, false), + "1.0000000000000001e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 18, false), + "1.00000000000000009e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 19, false), + "1.000000000000000091e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 20, false), + "1.0000000000000000906e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 21, false), + "1.00000000000000009060e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 22, false), + "1.000000000000000090597e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 23, false), + "1.0000000000000000905970e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 24, false), + "1.00000000000000009059697e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 25, false), + "1.000000000000000090596966e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 26, false), + "1.0000000000000000905969664e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 27, false), + "1.00000000000000009059696640e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 30, false), + "1.00000000000000009059696640000e25"); + + assert_eq!(to_string(f, 1.0e-6, Minus, 1, false), "1e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 2, false), "1.0e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 16, false), + "1.000000000000000e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 17, false), + "9.9999999999999995e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 18, false), + "9.99999999999999955e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 19, false), + "9.999999999999999547e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 20, false), + "9.9999999999999995475e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 30, false), + "9.99999999999999954748111825886e-7"); assert_eq!(to_string(f, 1.0e-6, Minus, 40, false), "9.999999999999999547481118258862586856139e-7"); assert_eq!(to_string(f, 1.0e-6, Minus, 50, false), @@ -865,35 +964,41 @@ pub fn to_exact_exp_str_test(mut f_: F) assert_eq!(to_string(f, 1.0e-6, Minus, 70, false), "9.999999999999999547481118258862586856139387236908078193664550781250000e-7"); - assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 8, false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 16, false), "3.402823466385289e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 32, false), "3.4028234663852885981170418348452e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 8, false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 16, false), + "3.402823466385289e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 32, false), + "3.4028234663852885981170418348452e38"); assert_eq!(to_string(f, f32::MAX, Minus, 64, false), "3.402823466385288598117041834845169254400000000000000000000000000e38"); let minf32 = f32::ldexp(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 1, false), "1e-45"); - assert_eq!(to_string(f, minf32, Minus, 2, false), "1.4e-45"); - assert_eq!(to_string(f, minf32, Minus, 4, false), "1.401e-45"); - assert_eq!(to_string(f, minf32, Minus, 8, false), "1.4012985e-45"); - assert_eq!(to_string(f, minf32, Minus, 16, false), "1.401298464324817e-45"); - assert_eq!(to_string(f, minf32, Minus, 32, false), "1.4012984643248170709237295832899e-45"); - assert_eq!(to_string(f, minf32, Minus, 64, false), + assert_eq!(to_string(f, minf32, Minus, 1, false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, 2, false), "1.4e-45"); + assert_eq!(to_string(f, minf32, Minus, 4, false), "1.401e-45"); + assert_eq!(to_string(f, minf32, Minus, 8, false), "1.4012985e-45"); + assert_eq!(to_string(f, minf32, Minus, 16, false), + "1.401298464324817e-45"); + assert_eq!(to_string(f, minf32, Minus, 32, false), + "1.4012984643248170709237295832899e-45"); + assert_eq!(to_string(f, minf32, Minus, 64, false), "1.401298464324817070923729583289916131280261941876515771757068284e-45"); assert_eq!(to_string(f, minf32, Minus, 128, false), "1.401298464324817070923729583289916131280261941876515771757068283\ 8897910826858606014866381883621215820312500000000000000000000000e-45"); - assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 8, false), "1.7976931e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 16, false), "1.797693134862316e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 32, false), "1.7976931348623157081452742373170e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 64, false), + assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 8, false), "1.7976931e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 16, false), + "1.797693134862316e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 32, false), + "1.7976931348623157081452742373170e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 64, false), "1.797693134862315708145274237317043567980705675258449965989174768e308"); assert_eq!(to_string(f, f64::MAX, Minus, 128, false), "1.797693134862315708145274237317043567980705675258449965989174768\ @@ -915,23 +1020,25 @@ pub fn to_exact_exp_str_test(mut f_: F) // okay, this is becoming tough. fortunately for us, this is almost the worst case. let minf64 = f64::ldexp(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 1, false), "5e-324"); - assert_eq!(to_string(f, minf64, Minus, 2, false), "4.9e-324"); - assert_eq!(to_string(f, minf64, Minus, 4, false), "4.941e-324"); - assert_eq!(to_string(f, minf64, Minus, 8, false), "4.9406565e-324"); - assert_eq!(to_string(f, minf64, Minus, 16, false), "4.940656458412465e-324"); - assert_eq!(to_string(f, minf64, Minus, 32, false), "4.9406564584124654417656879286822e-324"); - assert_eq!(to_string(f, minf64, Minus, 64, false), + assert_eq!(to_string(f, minf64, Minus, 1, false), "5e-324"); + assert_eq!(to_string(f, minf64, Minus, 2, false), "4.9e-324"); + assert_eq!(to_string(f, minf64, Minus, 4, false), "4.941e-324"); + assert_eq!(to_string(f, minf64, Minus, 8, false), "4.9406565e-324"); + assert_eq!(to_string(f, minf64, Minus, 16, false), + "4.940656458412465e-324"); + assert_eq!(to_string(f, minf64, Minus, 32, false), + "4.9406564584124654417656879286822e-324"); + assert_eq!(to_string(f, minf64, Minus, 64, false), "4.940656458412465441765687928682213723650598026143247644255856825e-324"); - assert_eq!(to_string(f, minf64, Minus, 128, false), + assert_eq!(to_string(f, minf64, Minus, 128, false), "4.940656458412465441765687928682213723650598026143247644255856825\ 0067550727020875186529983636163599237979656469544571773092665671e-324"); - assert_eq!(to_string(f, minf64, Minus, 256, false), + assert_eq!(to_string(f, minf64, Minus, 256, false), "4.940656458412465441765687928682213723650598026143247644255856825\ 0067550727020875186529983636163599237979656469544571773092665671\ 0355939796398774796010781878126300713190311404527845817167848982\ 1036887186360569987307230500063874091535649843873124733972731696e-324"); - assert_eq!(to_string(f, minf64, Minus, 512, false), + assert_eq!(to_string(f, minf64, Minus, 512, false), "4.940656458412465441765687928682213723650598026143247644255856825\ 0067550727020875186529983636163599237979656469544571773092665671\ 0355939796398774796010781878126300713190311404527845817167848982\ @@ -959,151 +1066,180 @@ pub fn to_exact_exp_str_test(mut f_: F) 0000000000000000000000000000000000000000000000000000000000000000e-324"); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); - assert_eq!(to_string(f, 1.0e-1, Minus, 80000, false), + assert_eq!(to_string(f, 0.0, Minus, 80000, false), + format!("0.{:0>79999}e0", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), + format!("1.{:0>79999}e1", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), + format!("1.{:0>79999}e0", "")); + assert_eq!(to_string(f, 1.0e-1, Minus, 80000, false), format!("1.000000000000000055511151231257827021181583404541015625{:0>79945}\ - e-1", "")); + e-1", + "")); assert_eq!(to_string(f, 1.0e-20, Minus, 80000, false), format!("9.999999999999999451532714542095716517295037027873924471077157760\ - 66783064379706047475337982177734375{:0>79901}e-21", "")); + 66783064379706047475337982177734375{:0>79901}e-21", + "")); } pub fn to_exact_fixed_str_test(mut f_: F) - where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) +{ use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize, upper: bool) -> String - where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { - to_string_with_parts(|buf, parts| to_exact_fixed_str(|d,b,l| f(d,b,l), v, sign, - frac_digits, upper, buf, parts)) + where T: DecodableFloat, + F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) + { + to_string_with_parts(|buf, parts| { + to_exact_fixed_str(|d, b, l| f(d, b, l), + v, + sign, + frac_digits, + upper, + buf, + parts) + }) } let f = &mut f_; - assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0, false), "-0"); - assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); - - assert_eq!(to_string(f, 1.0/0.0, Minus, 0, false), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusRaw, 1, true), "inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlus, 8, false), "+inf"); - assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, 64, true), "+inf"); - assert_eq!(to_string(f, 0.0/0.0, Minus, 0, false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusRaw, 1, true), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, 64, true), "NaN"); - assert_eq!(to_string(f, -1.0/0.0, Minus, 0, false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusRaw, 1, true), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlus, 8, false), "-inf"); - assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, 64, true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 0, false), "3"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3"); - assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3"); - assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3"); - assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3"); + assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0, false), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1, true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 8, false), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 64, true), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0, false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64, true), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0, false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8, false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64, true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0, false), "3"); + assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3"); + assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3"); + assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3"); assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0, false), "-3"); - assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.1"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); - assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); - - assert_eq!(to_string(f, 0.195, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.195, MinusRaw, 0, false), "0"); - assert_eq!(to_string(f, 0.195, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 0, false), "+0"); - assert_eq!(to_string(f, -0.195, Minus, 0, false), "-0"); - assert_eq!(to_string(f, -0.195, MinusRaw, 0, false), "-0"); - assert_eq!(to_string(f, -0.195, MinusPlus, 0, false), "-0"); + assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.1"); + assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); + + assert_eq!(to_string(f, 0.195, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.195, MinusRaw, 0, false), "0"); + assert_eq!(to_string(f, 0.195, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 0, false), "+0"); + assert_eq!(to_string(f, -0.195, Minus, 0, false), "-0"); + assert_eq!(to_string(f, -0.195, MinusRaw, 0, false), "-0"); + assert_eq!(to_string(f, -0.195, MinusPlus, 0, false), "-0"); assert_eq!(to_string(f, -0.195, MinusPlusRaw, 0, false), "-0"); - assert_eq!(to_string(f, 0.195, Minus, 1, true), "0.2"); - assert_eq!(to_string(f, 0.195, MinusRaw, 2, true), "0.20"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+0.195"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 4, true), "+0.1950"); - assert_eq!(to_string(f, -0.195, Minus, 5, true), "-0.19500"); - assert_eq!(to_string(f, -0.195, MinusRaw, 6, true), "-0.195000"); - assert_eq!(to_string(f, -0.195, MinusPlus, 7, true), "-0.1950000"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 8, true), "-0.19500000"); - - assert_eq!(to_string(f, 999.5, Minus, 0, false), "1000"); - assert_eq!(to_string(f, 999.5, Minus, 1, false), "999.5"); - assert_eq!(to_string(f, 999.5, Minus, 2, false), "999.50"); - assert_eq!(to_string(f, 999.5, Minus, 3, false), "999.500"); - assert_eq!(to_string(f, 999.5, Minus, 30, false), "999.500000000000000000000000000000"); + assert_eq!(to_string(f, 0.195, Minus, 1, true), "0.2"); + assert_eq!(to_string(f, 0.195, MinusRaw, 2, true), "0.20"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+0.195"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 4, true), "+0.1950"); + assert_eq!(to_string(f, -0.195, Minus, 5, true), "-0.19500"); + assert_eq!(to_string(f, -0.195, MinusRaw, 6, true), "-0.195000"); + assert_eq!(to_string(f, -0.195, MinusPlus, 7, true), "-0.1950000"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 8, true), "-0.19500000"); + + assert_eq!(to_string(f, 999.5, Minus, 0, false), "1000"); + assert_eq!(to_string(f, 999.5, Minus, 1, false), "999.5"); + assert_eq!(to_string(f, 999.5, Minus, 2, false), "999.50"); + assert_eq!(to_string(f, 999.5, Minus, 3, false), "999.500"); + assert_eq!(to_string(f, 999.5, Minus, 30, false), + "999.500000000000000000000000000000"); assert_eq!(to_string(f, 0.5, Minus, 0, false), "1"); assert_eq!(to_string(f, 0.5, Minus, 1, false), "0.5"); assert_eq!(to_string(f, 0.5, Minus, 2, false), "0.50"); assert_eq!(to_string(f, 0.5, Minus, 3, false), "0.500"); - assert_eq!(to_string(f, 0.95, Minus, 0, false), "1"); - assert_eq!(to_string(f, 0.95, Minus, 1, false), "0.9"); // because it really is less than 0.95 - assert_eq!(to_string(f, 0.95, Minus, 2, false), "0.95"); - assert_eq!(to_string(f, 0.95, Minus, 3, false), "0.950"); + assert_eq!(to_string(f, 0.95, Minus, 0, false), "1"); + assert_eq!(to_string(f, 0.95, Minus, 1, false), "0.9"); // because it really is less than 0.95 + assert_eq!(to_string(f, 0.95, Minus, 2, false), "0.95"); + assert_eq!(to_string(f, 0.95, Minus, 3, false), "0.950"); assert_eq!(to_string(f, 0.95, Minus, 10, false), "0.9500000000"); - assert_eq!(to_string(f, 0.95, Minus, 30, false), "0.949999999999999955591079014994"); - - assert_eq!(to_string(f, 0.095, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.095, Minus, 1, false), "0.1"); - assert_eq!(to_string(f, 0.095, Minus, 2, false), "0.10"); - assert_eq!(to_string(f, 0.095, Minus, 3, false), "0.095"); - assert_eq!(to_string(f, 0.095, Minus, 4, false), "0.0950"); + assert_eq!(to_string(f, 0.95, Minus, 30, false), + "0.949999999999999955591079014994"); + + assert_eq!(to_string(f, 0.095, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.095, Minus, 1, false), "0.1"); + assert_eq!(to_string(f, 0.095, Minus, 2, false), "0.10"); + assert_eq!(to_string(f, 0.095, Minus, 3, false), "0.095"); + assert_eq!(to_string(f, 0.095, Minus, 4, false), "0.0950"); assert_eq!(to_string(f, 0.095, Minus, 10, false), "0.0950000000"); - assert_eq!(to_string(f, 0.095, Minus, 30, false), "0.095000000000000001110223024625"); - - assert_eq!(to_string(f, 0.0095, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.0095, Minus, 1, false), "0.0"); - assert_eq!(to_string(f, 0.0095, Minus, 2, false), "0.01"); - assert_eq!(to_string(f, 0.0095, Minus, 3, false), "0.009"); // really is less than 0.0095 - assert_eq!(to_string(f, 0.0095, Minus, 4, false), "0.0095"); - assert_eq!(to_string(f, 0.0095, Minus, 5, false), "0.00950"); + assert_eq!(to_string(f, 0.095, Minus, 30, false), + "0.095000000000000001110223024625"); + + assert_eq!(to_string(f, 0.0095, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.0095, Minus, 1, false), "0.0"); + assert_eq!(to_string(f, 0.0095, Minus, 2, false), "0.01"); + assert_eq!(to_string(f, 0.0095, Minus, 3, false), "0.009"); // really is less than 0.0095 + assert_eq!(to_string(f, 0.0095, Minus, 4, false), "0.0095"); + assert_eq!(to_string(f, 0.0095, Minus, 5, false), "0.00950"); assert_eq!(to_string(f, 0.0095, Minus, 10, false), "0.0095000000"); - assert_eq!(to_string(f, 0.0095, Minus, 30, false), "0.009499999999999999764077607267"); + assert_eq!(to_string(f, 0.0095, Minus, 30, false), + "0.009499999999999999764077607267"); - assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0"); - assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000"); assert_eq!(to_string(f, 7.5e-11, Minus, 10, false), "0.0000000001"); assert_eq!(to_string(f, 7.5e-11, Minus, 11, false), "0.00000000007"); // ditto assert_eq!(to_string(f, 7.5e-11, Minus, 12, false), "0.000000000075"); assert_eq!(to_string(f, 7.5e-11, Minus, 13, false), "0.0000000000750"); - assert_eq!(to_string(f, 7.5e-11, Minus, 20, false), "0.00000000007500000000"); - assert_eq!(to_string(f, 7.5e-11, Minus, 30, false), "0.000000000074999999999999999501"); - - assert_eq!(to_string(f, 1.0e25, Minus, 0, false), "10000000000000000905969664"); - assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "10000000000000000905969664.0"); - assert_eq!(to_string(f, 1.0e25, Minus, 3, false), "10000000000000000905969664.000"); - - assert_eq!(to_string(f, 1.0e-6, Minus, 0, false), "0"); - assert_eq!(to_string(f, 1.0e-6, Minus, 3, false), "0.000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 6, false), "0.000001"); - assert_eq!(to_string(f, 1.0e-6, Minus, 9, false), "0.000001000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 20, false), + "0.00000000007500000000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 30, false), + "0.000000000074999999999999999501"); + + assert_eq!(to_string(f, 1.0e25, Minus, 0, false), + "10000000000000000905969664"); + assert_eq!(to_string(f, 1.0e25, Minus, 1, false), + "10000000000000000905969664.0"); + assert_eq!(to_string(f, 1.0e25, Minus, 3, false), + "10000000000000000905969664.000"); + + assert_eq!(to_string(f, 1.0e-6, Minus, 0, false), "0"); + assert_eq!(to_string(f, 1.0e-6, Minus, 3, false), "0.000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 6, false), "0.000001"); + assert_eq!(to_string(f, 1.0e-6, Minus, 9, false), "0.000001000"); assert_eq!(to_string(f, 1.0e-6, Minus, 12, false), "0.000001000000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 22, false), "0.0000010000000000000000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 23, false), "0.00000099999999999999995"); - assert_eq!(to_string(f, 1.0e-6, Minus, 24, false), "0.000000999999999999999955"); - assert_eq!(to_string(f, 1.0e-6, Minus, 25, false), "0.0000009999999999999999547"); - assert_eq!(to_string(f, 1.0e-6, Minus, 35, false), "0.00000099999999999999995474811182589"); + assert_eq!(to_string(f, 1.0e-6, Minus, 22, false), + "0.0000010000000000000000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 23, false), + "0.00000099999999999999995"); + assert_eq!(to_string(f, 1.0e-6, Minus, 24, false), + "0.000000999999999999999955"); + assert_eq!(to_string(f, 1.0e-6, Minus, 25, false), + "0.0000009999999999999999547"); + assert_eq!(to_string(f, 1.0e-6, Minus, 35, false), + "0.00000099999999999999995474811182589"); assert_eq!(to_string(f, 1.0e-6, Minus, 45, false), "0.000000999999999999999954748111825886258685614"); assert_eq!(to_string(f, 1.0e-6, Minus, 55, false), @@ -1121,14 +1257,15 @@ pub fn to_exact_fixed_str_test(mut f_: F) "340282346638528859811704183484516925440.00"); let minf32 = f32::ldexp(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 0, false), "0"); - assert_eq!(to_string(f, minf32, Minus, 1, false), "0.0"); - assert_eq!(to_string(f, minf32, Minus, 2, false), "0.00"); - assert_eq!(to_string(f, minf32, Minus, 4, false), "0.0000"); - assert_eq!(to_string(f, minf32, Minus, 8, false), "0.00000000"); - assert_eq!(to_string(f, minf32, Minus, 16, false), "0.0000000000000000"); - assert_eq!(to_string(f, minf32, Minus, 32, false), "0.00000000000000000000000000000000"); - assert_eq!(to_string(f, minf32, Minus, 64, false), + assert_eq!(to_string(f, minf32, Minus, 0, false), "0"); + assert_eq!(to_string(f, minf32, Minus, 1, false), "0.0"); + assert_eq!(to_string(f, minf32, Minus, 2, false), "0.00"); + assert_eq!(to_string(f, minf32, Minus, 4, false), "0.0000"); + assert_eq!(to_string(f, minf32, Minus, 8, false), "0.00000000"); + assert_eq!(to_string(f, minf32, Minus, 16, false), "0.0000000000000000"); + assert_eq!(to_string(f, minf32, Minus, 32, false), + "0.00000000000000000000000000000000"); + assert_eq!(to_string(f, minf32, Minus, 64, false), "0.0000000000000000000000000000000000000000000014012984643248170709"); assert_eq!(to_string(f, minf32, Minus, 128, false), "0.0000000000000000000000000000000000000000000014012984643248170709\ @@ -1178,13 +1315,17 @@ pub fn to_exact_fixed_str_test(mut f_: F) 1014510378627381672509558373897335989937"); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("10.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e-1, Minus, 80000, false), - format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "")); + assert_eq!(to_string(f, 0.0, Minus, 80000, false), + format!("0.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), + format!("10.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), + format!("1.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e-1, Minus, 80000, false), + format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", + "")); assert_eq!(to_string(f, 1.0e-20, Minus, 80000, false), format!("0.0000000000000000000099999999999999994515327145420957165172950370\ - 2787392447107715776066783064379706047475337982177734375{:0>79881}", "")); + 2787392447107715776066783064379706047475337982177734375{:0>79881}", + "")); } - diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcoretest/num/flt2dec/strategy/dragon.rs index 79dcca7671a2..ea954f9cd336 100644 --- a/src/libcoretest/num/flt2dec/strategy/dragon.rs +++ b/src/libcoretest/num/flt2dec/strategy/dragon.rs @@ -129,4 +129,3 @@ fn test_to_exact_exp_str() { fn test_to_exact_fixed_str() { to_exact_fixed_str_test(format_exact); } - diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcoretest/num/flt2dec/strategy/grisu.rs index 2d4afceda191..08744b6fcdb1 100644 --- a/src/libcoretest/num/flt2dec/strategy/grisu.rs +++ b/src/libcoretest/num/flt2dec/strategy/grisu.rs @@ -18,12 +18,16 @@ fn test_cached_power() { assert_eq!(CACHED_POW10.first().unwrap().1, CACHED_POW10_FIRST_E); assert_eq!(CACHED_POW10.last().unwrap().1, CACHED_POW10_LAST_E); - for e in -1137..961 { // full range for f64 + for e in -1137..961 { + // full range for f64 let low = ALPHA - e - 64; let high = GAMMA - e - 64; let (_k, cached) = cached_power(low, high); assert!(low <= cached.e && cached.e <= high, - "cached_power({}, {}) = {:?} is incorrect", low, high, cached); + "cached_power({}, {}) = {:?} is incorrect", + low, + high, + cached); } } @@ -53,7 +57,8 @@ fn shortest_random_equivalence_test() { f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); } -#[test] #[ignore] // it is too expensive +#[test] +#[ignore] // it is too expensive fn shortest_f32_exhaustive_equivalence_test() { // it is hard to directly test the optimality of the output, but we can at least test if // two different algorithms agree to each other. @@ -66,13 +71,13 @@ fn shortest_f32_exhaustive_equivalence_test() { f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); } -#[test] #[ignore] // it is too expensive +#[test] +#[ignore] // it is too expensive fn shortest_f64_hard_random_equivalence_test() { // this again probably has to use appropriate rustc flags. use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, - MAX_SIG_DIGITS, 100_000_000); + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000); } #[test] @@ -90,7 +95,9 @@ fn exact_f32_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; for k in 1..21 { f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + |d, buf| fallback(d, buf, i16::MIN), + k, + 1_000); } } @@ -99,7 +106,9 @@ fn exact_f64_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; for k in 1..21 { f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + |d, buf| fallback(d, buf, i16::MIN), + k, + 1_000); } } @@ -178,4 +187,3 @@ fn test_to_exact_exp_str() { fn test_to_exact_fixed_str() { to_exact_fixed_str_test(format_exact); } - diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 4834c0e072c9..6924629f11eb 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -44,18 +44,18 @@ pub fn test_num(ten: T, two: T) where + Rem + Debug + Copy { - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); } #[test] fn from_str_issue7588() { - let u : Option = u8::from_str_radix("1000", 10).ok(); + let u: Option = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); - let s : Option = i16::from_str_radix("80000", 10).ok(); + let s: Option = i16::from_str_radix("80000", 10).ok(); assert_eq!(s, None); } @@ -97,7 +97,8 @@ fn test_int_from_str_overflow() { #[test] fn test_leading_plus() { assert_eq!("+127".parse::().ok(), Some(127)); - assert_eq!("+9223372036854775807".parse::().ok(), Some(9223372036854775807)); + assert_eq!("+9223372036854775807".parse::().ok(), + Some(9223372036854775807)); } #[test] diff --git a/src/libcoretest/ops.rs b/src/libcoretest/ops.rs index 33674a3abd87..d4b1f2f8692b 100644 --- a/src/libcoretest/ops.rs +++ b/src/libcoretest/ops.rs @@ -14,18 +14,17 @@ use core::ops::{Range, RangeFull, RangeFrom, RangeTo}; // Overhead of dtors struct HasDtor { - _x: isize + _x: isize, } impl Drop for HasDtor { - fn drop(&mut self) { - } + fn drop(&mut self) {} } #[bench] fn alloc_obj_with_dtor(b: &mut Bencher) { b.iter(|| { - HasDtor { _x : 10 }; + HasDtor { _x: 10 }; }) } @@ -33,7 +32,10 @@ fn alloc_obj_with_dtor(b: &mut Bencher) { #[test] fn test_range() { - let r = Range { start: 2, end: 10 }; + let r = Range { + start: 2, + end: 10, + }; let mut count = 0; for (i, ri) in r.enumerate() { assert!(ri == i + 2); diff --git a/src/libcoretest/option.rs b/src/libcoretest/option.rs index 51b0655f680f..939446d8016b 100644 --- a/src/libcoretest/option.rs +++ b/src/libcoretest/option.rs @@ -40,11 +40,11 @@ fn test_get_resource() { use core::cell::RefCell; struct R { - i: Rc>, + i: Rc>, } - impl Drop for R { - fn drop(&mut self) { + impl Drop for R { + fn drop(&mut self) { let ii = &*self.i; let i = *ii.borrow(); *ii.borrow_mut() = i + 1; @@ -52,9 +52,7 @@ fn test_get_resource() { } fn r(i: Rc>) -> R { - R { - i: i - } + R { i: i } } let i = Rc::new(RefCell::new(0)); @@ -78,7 +76,8 @@ fn test_option_dance() { assert!(y.is_none()); } -#[test] #[should_panic] +#[test] +#[should_panic] fn test_option_too_much_dance() { struct A; let mut y = Some(A); @@ -218,7 +217,7 @@ fn test_mut_iter() { fn test_ord() { let small = Some(1.0f64); let big = Some(5.0f64); - let nan = Some(0.0f64/0.0); + let nan = Some(0.0f64 / 0.0); assert!(!(nan < big)); assert!(!(nan > big)); assert!(small < big); @@ -234,14 +233,21 @@ fn test_collect() { let v: Option> = (0..3).map(|x| Some(x)).collect(); assert!(v == Some(vec![0, 1, 2])); - let v: Option> = (0..3).map(|x| { - if x > 1 { None } else { Some(x) } - }).collect(); + let v: Option> = (0..3) + .map(|x| { + if x > 1 { + None + } else { + Some(x) + } + }) + .collect(); assert!(v == None); // test that it does not take more elements than it needs - let mut functions: [Box Option<()>>; 3] = - [box || Some(()), box || None, box || panic!()]; + let mut functions: [Box Option<()>>; 3] = [box || Some(()), + box || None, + box || panic!()]; let v: Option> = functions.iter_mut().map(|f| (*f)()).collect(); diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index 343db93d4a97..bf49e4294060 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -15,9 +15,9 @@ fn test() { unsafe { struct Pair { fst: isize, - snd: isize + snd: isize, }; - let mut p = Pair {fst: 10, snd: 20}; + let mut p = Pair { fst: 10, snd: 20 }; let pptr: *mut Pair = &mut p; let iptr: *mut isize = pptr as *mut isize; assert_eq!(*iptr, 10); @@ -25,7 +25,7 @@ fn test() { assert_eq!(*iptr, 30); assert_eq!(p.fst, 30); - *pptr = Pair {fst: 50, snd: 60}; + *pptr = Pair { fst: 50, snd: 60 }; assert_eq!(*iptr, 50); assert_eq!(p.fst, 50); assert_eq!(p.snd, 60); @@ -34,17 +34,11 @@ fn test() { let mut v1 = vec![0u16, 0u16, 0u16]; copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1); - assert!((v1[0] == 0u16 && - v1[1] == 32001u16 && - v1[2] == 0u16)); + assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16)); copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1); - assert!((v1[0] == 32002u16 && - v1[1] == 32001u16 && - v1[2] == 0u16)); + assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16)); copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1); - assert!((v1[0] == 32002u16 && - v1[1] == 32001u16 && - v1[2] == 32000u16)); + assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16)); } } @@ -133,7 +127,7 @@ fn test_ptr_addition() { #[test] fn test_ptr_subtraction() { unsafe { - let xs = vec![0,1,2,3,4,5,6,7,8,9]; + let xs = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let mut idx = 9; let ptr = xs.as_ptr(); @@ -151,7 +145,7 @@ fn test_ptr_subtraction() { m_ptr = m_ptr.offset(-1); } - assert_eq!(xs_mut, [0,2,4,6,8,10,12,14,16,18]); + assert_eq!(xs_mut, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]); } } @@ -159,7 +153,9 @@ fn test_ptr_subtraction() { fn test_set_memory() { let mut xs = [0u8; 20]; let ptr = xs.as_mut_ptr(); - unsafe { write_bytes(ptr, 5u8, xs.len()); } + unsafe { + write_bytes(ptr, 5u8, xs.len()); + } assert!(xs == [5u8; 20]); } diff --git a/src/libcoretest/result.rs b/src/libcoretest/result.rs index 6e9f653dcd8a..a9919ea4f514 100644 --- a/src/libcoretest/result.rs +++ b/src/libcoretest/result.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn op1() -> Result { Ok(666) } -fn op2() -> Result { Err("sadface") } +fn op1() -> Result { + Ok(666) +} +fn op2() -> Result { + Err("sadface") +} #[test] fn test_and() { @@ -18,13 +22,14 @@ fn test_and() { "bad"); assert_eq!(op2().and(Ok(667)).unwrap_err(), "sadface"); - assert_eq!(op2().and(Err::("bad")).unwrap_err(), + assert_eq!(op2().and(Err::("bad")).unwrap_err(), "sadface"); } #[test] fn test_and_then() { - assert_eq!(op1().and_then(|i| Ok::(i + 1)).unwrap(), 667); + assert_eq!(op1().and_then(|i| Ok::(i + 1)).unwrap(), + 667); assert_eq!(op1().and_then(|_| Err::("bad")).unwrap_err(), "bad"); @@ -45,10 +50,13 @@ fn test_or() { #[test] fn test_or_else() { - assert_eq!(op1().or_else(|_| Ok::(667)).unwrap(), 666); - assert_eq!(op1().or_else(|e| Err::(e)).unwrap(), 666); + assert_eq!(op1().or_else(|_| Ok::(667)).unwrap(), + 666); + assert_eq!(op1().or_else(|e| Err::(e)).unwrap(), + 666); - assert_eq!(op2().or_else(|_| Ok::(667)).unwrap(), 667); + assert_eq!(op2().or_else(|_| Ok::(667)).unwrap(), + 667); assert_eq!(op2().or_else(|e| Err::(e)).unwrap_err(), "sadface"); } @@ -73,14 +81,21 @@ fn test_collect() { let v: Result, ()> = (0..3).map(|x| Ok::(x)).collect(); assert!(v == Ok(vec![0, 1, 2])); - let v: Result, isize> = (0..3).map(|x| { - if x > 1 { Err(x) } else { Ok(x) } - }).collect(); + let v: Result, isize> = (0..3) + .map(|x| { + if x > 1 { + Err(x) + } else { + Ok(x) + } + }) + .collect(); assert!(v == Err(2)); // test that it does not take more elements than it needs - let mut functions: [Box Result<(), isize>>; 3] = - [box || Ok(()), box || Err(1), box || panic!()]; + let mut functions: [Box Result<(), isize>>; 3] = [box || Ok(()), + box || Err(1), + box || panic!()]; let v: Result, isize> = functions.iter_mut().map(|f| (*f)()).collect(); assert!(v == Err(1)); @@ -135,7 +150,7 @@ pub fn test_unwrap_or_else_panic() { } let bad_err: Result = Err("Unrecoverable mess."); - let _ : isize = bad_err.unwrap_or_else(handler); + let _: isize = bad_err.unwrap_or_else(handler); } diff --git a/src/libcoretest/tuple.rs b/src/libcoretest/tuple.rs index 4fe5e0a740bf..17d5d4a987ea 100644 --- a/src/libcoretest/tuple.rs +++ b/src/libcoretest/tuple.rs @@ -21,7 +21,7 @@ fn test_clone() { fn test_tuple_cmp() { let (small, big) = ((1, 2, 3), (3, 2, 1)); - let nan = 0.0f64/0.0; + let nan = 0.0f64 / 0.0; // PartialEq assert_eq!(small, small); From 3036d78a7fe19346c45dd67307d8da41cde5fb34 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Tue, 19 Apr 2016 12:25:28 -0700 Subject: [PATCH 002/179] Efficient trie lookup for boolean Unicode properties Replace binary search of ranges with trie lookup using leaves of 64-bit bitmap chunks. Benchmarks suggest this is approximately 10x faster than the bsearch approach. --- src/etc/unicode.py | 111 +- src/librustc_unicode/tables.rs | 2391 +++++++++++++++++--------------- 2 files changed, 1368 insertions(+), 1134 deletions(-) diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 5a7632868e46..406f5380d469 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -307,12 +307,114 @@ def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True, format_table_content(f, data, 8) f.write("\n ];\n\n") +def emit_trie_lookup_range_table(f): + f.write(""" +pub struct BoolTrie { + // 0..0x800 (corresponding to 1 and 2 byte utf-8 sequences) + r1: [u64; 32], // leaves + + // 0x800..0x10000 (corresponding to 3 byte utf-8 sequences) + r2: [u8; 1024], // first level + r3: &'static [u64], // leaves + + // 0x10000..0x110000 (corresponding to 4 byte utf-8 sequences) + r4: [u8; 272], // first level + r5: &'static [u8], // second level + r6: &'static [u64], // leaves +} + +fn trie_range_leaf(c: usize, bitmap_chunk: u64) -> bool { + ((bitmap_chunk >> (c & 63)) & 1) != 0 +} + +fn trie_lookup_range_table(c: char, r: &'static BoolTrie) -> bool { + let c = c as usize; + if c < 0x800 { + trie_range_leaf(c, r.r1[c >> 8]) + } else if c < 0x10000 { + let child = r.r2[c >> 6]; + trie_range_leaf(c, r.r3[child as usize]) + } else { + let child = r.r4[c >> 12]; + let leaf = r.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; + trie_range_leaf(c, r.r6[leaf as usize]) + } +}\n +""") + +def compute_trie(rawdata, chunksize): + root = [] + childmap = {} + child_data = [] + for i in range(len(rawdata) / chunksize): + data = rawdata[i * chunksize: (i + 1) * chunksize] + child = '|'.join(map(str, data)) + if child not in childmap: + childmap[child] = len(childmap) + child_data.extend(data) + root.append(childmap[child]) + return (root, child_data) + +def emit_bool_trie(f, name, t_data, is_pub=True): + CHUNK = 64 + rawdata = [False] * 0x110000; + for (lo, hi) in t_data: + for cp in range(lo, hi + 1): + rawdata[cp] = True + + # convert to bitmap chunks of 64 bits each + chunks = [] + for i in range(0x110000 / CHUNK): + chunk = 0 + for j in range(64): + if rawdata[i * 64 + j]: + chunk |= 1 << j + chunks.append(chunk) + + pub_string = "" + if is_pub: + pub_string = "pub " + f.write(" %sconst %s: &'static super::BoolTrie = &super::BoolTrie {\n" % (pub_string, name)) + f.write(" r1: [\n") + data = ','.join('0x%016x' % chunk for chunk in chunks[0:0x800 / CHUNK]) + format_table_content(f, data, 12) + f.write("\n ],\n") + + # 0x800..0x10000 trie + (r2, r3) = compute_trie(chunks[0x800 / CHUNK : 0x10000 / CHUNK], 64 / CHUNK) + f.write(" r2: [\n") + data = ','.join(str(node) for node in [255] * 32 + r2) + format_table_content(f, data, 12) + f.write("\n ],\n") + f.write(" r3: &[\n") + data = ','.join('0x%016x' % chunk for chunk in r3) + format_table_content(f, data, 12) + f.write("\n ],\n") + + # 0x10000..0x110000 trie + (mid, r6) = compute_trie(chunks[0x10000 / CHUNK : 0x110000 / CHUNK], 64 / CHUNK) + (r4, r5) = compute_trie(mid, 64) + f.write(" r4: [\n") + data = ','.join(str(node) for node in [255] * 16 + r4) + format_table_content(f, data, 12) + f.write("\n ],\n") + f.write(" r5: &[\n") + data = ','.join(str(node) for node in r5) + format_table_content(f, data, 12) + f.write("\n ],\n") + f.write(" r6: &[\n") + data = ','.join('0x%016x' % chunk for chunk in r6) + format_table_content(f, data, 12) + f.write("\n ],\n") + + f.write(" };\n\n") + def emit_property_module(f, mod, tbl, emit): f.write("pub mod %s {\n" % mod) for cat in sorted(emit): - emit_table(f, "%s_table" % cat, tbl[cat]) + emit_bool_trie(f, "%s_table" % cat, tbl[cat]) f.write(" pub fn %s(c: char) -> bool {\n" % cat) - f.write(" super::bsearch_range_table(c, %s_table)\n" % cat) + f.write(" super::trie_lookup_range_table(c, %s_table)\n" % cat) f.write(" }\n\n") f.write("}\n\n") @@ -402,8 +504,9 @@ def emit_norm_module(f, canon, compat, combine, norm_props): norm_props = load_properties("DerivedNormalizationProps.txt", ["Full_Composition_Exclusion"]) - # bsearch_range_table is used in all the property modules below - emit_bsearch_range_table(rf) + # trie_lookup_table is used in all the property modules below + emit_trie_lookup_range_table(rf) + # emit_bsearch_range_table(rf) # category tables for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \ diff --git a/src/librustc_unicode/tables.rs b/src/librustc_unicode/tables.rs index ad17016eae8c..a3afa3b56ec9 100644 --- a/src/librustc_unicode/tables.rs +++ b/src/librustc_unicode/tables.rs @@ -16,1187 +16,1318 @@ /// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on. pub const UNICODE_VERSION: (u64, u64, u64) = (8, 0, 0); -fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool { - use core::cmp::Ordering::{Equal, Less, Greater}; - r.binary_search_by(|&(lo, hi)| { - if c < lo { - Greater - } else if hi < c { - Less - } else { - Equal - } - }) - .is_ok() +pub struct BoolTrie { + // 0..0x800 (corresponding to 1 and 2 byte utf-8 sequences) + r1: [u64; 32], // leaves + + // 0x800..0x10000 (corresponding to 3 byte utf-8 sequences) + r2: [u8; 1024], // first level + r3: &'static [u64], // leaves + + // 0x10000..0x110000 (corresponding to 4 byte utf-8 sequences) + r4: [u8; 272], // first level + r5: &'static [u8], // second level + r6: &'static [u64], // leaves +} + +fn trie_range_leaf(c: usize, bitmap_chunk: u64) -> bool { + ((bitmap_chunk >> (c & 63)) & 1) != 0 +} + +fn trie_lookup_range_table(c: char, r: &'static BoolTrie) -> bool { + let c = c as usize; + if c < 0x800 { + trie_range_leaf(c, r.r1[c >> 8]) + } else if c < 0x10000 { + let child = r.r2[c >> 6]; + trie_range_leaf(c, r.r3[child as usize]) + } else { + let child = r.r4[c >> 12]; + let leaf = r.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; + trie_range_leaf(c, r.r6[leaf as usize]) + } } pub mod general_category { - pub const Cc_table: &'static [(char, char)] = &[ - ('\0', '\u{1f}'), ('\u{7f}', '\u{9f}') - ]; + pub const Cc_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x00000000ffffffff, 0x8000000000000000, 0x00000000ffffffff, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ], + r3: &[ + 0x0000000000000000 + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000 + ], + }; pub fn Cc(c: char) -> bool { - super::bsearch_range_table(c, Cc_table) + super::trie_lookup_range_table(c, Cc_table) } - pub const N_table: &'static [(char, char)] = &[ - ('\u{30}', '\u{39}'), ('\u{660}', '\u{669}'), ('\u{6f0}', '\u{6f9}'), ('\u{7c0}', - '\u{7c9}'), ('\u{966}', '\u{96f}'), ('\u{9e6}', '\u{9ef}'), ('\u{a66}', '\u{a6f}'), - ('\u{ae6}', '\u{aef}'), ('\u{b66}', '\u{b6f}'), ('\u{be6}', '\u{bef}'), ('\u{c66}', - '\u{c6f}'), ('\u{ce6}', '\u{cef}'), ('\u{d66}', '\u{d6f}'), ('\u{de6}', '\u{def}'), - ('\u{e50}', '\u{e59}'), ('\u{ed0}', '\u{ed9}'), ('\u{f20}', '\u{f29}'), ('\u{1040}', - '\u{1049}'), ('\u{1090}', '\u{1099}'), ('\u{16ee}', '\u{16f0}'), ('\u{17e0}', '\u{17e9}'), - ('\u{1810}', '\u{1819}'), ('\u{1946}', '\u{194f}'), ('\u{19d0}', '\u{19d9}'), ('\u{1a80}', - '\u{1a89}'), ('\u{1a90}', '\u{1a99}'), ('\u{1b50}', '\u{1b59}'), ('\u{1bb0}', '\u{1bb9}'), - ('\u{1c40}', '\u{1c49}'), ('\u{1c50}', '\u{1c59}'), ('\u{2160}', '\u{2182}'), ('\u{2185}', - '\u{2188}'), ('\u{3007}', '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3038}', '\u{303a}'), - ('\u{a620}', '\u{a629}'), ('\u{a6e6}', '\u{a6ef}'), ('\u{a8d0}', '\u{a8d9}'), ('\u{a900}', - '\u{a909}'), ('\u{a9d0}', '\u{a9d9}'), ('\u{a9f0}', '\u{a9f9}'), ('\u{aa50}', '\u{aa59}'), - ('\u{abf0}', '\u{abf9}'), ('\u{ff10}', '\u{ff19}'), ('\u{10140}', '\u{10174}'), - ('\u{10341}', '\u{10341}'), ('\u{1034a}', '\u{1034a}'), ('\u{103d1}', '\u{103d5}'), - ('\u{104a0}', '\u{104a9}'), ('\u{11066}', '\u{1106f}'), ('\u{110f0}', '\u{110f9}'), - ('\u{11136}', '\u{1113f}'), ('\u{111d0}', '\u{111d9}'), ('\u{112f0}', '\u{112f9}'), - ('\u{114d0}', '\u{114d9}'), ('\u{11650}', '\u{11659}'), ('\u{116c0}', '\u{116c9}'), - ('\u{11730}', '\u{11739}'), ('\u{118e0}', '\u{118e9}'), ('\u{12400}', '\u{1246e}'), - ('\u{16a60}', '\u{16a69}'), ('\u{16b50}', '\u{16b59}'), ('\u{1d7ce}', '\u{1d7ff}') - ]; + pub const N_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x000003ff00000000, 0x0000000000000000, 0x03ff000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00000000000003ff + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3, 0, 0, 0, 0, + 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, + 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0 + ], + r3: &[ + 0x0000000000000000, 0x0000ffc000000000, 0x0000000003ff0000, 0x000003ff00000000, + 0x00000000000003ff, 0x0001c00000000000, 0x000000000000ffc0, 0x0000000003ff03ff, + 0x03ff000000000000, 0xffffffff00000000, 0x00000000000001e7, 0x070003fe00000080, + 0x03ff000003ff0000 + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 + ], + r5: &[ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, + 0, 0, 8, 0, 9, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, + 0x000003ff00000000, 0x0000ffc000000000, 0x03ff000000000000, 0xffc0000000000000, + 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, + 0xffffffffffffc000 + ], + }; pub fn N(c: char) -> bool { - super::bsearch_range_table(c, N_table) + super::trie_lookup_range_table(c, N_table) } } pub mod derived_property { - pub const Alphabetic_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), - ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), - ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', - '\u{2ee}'), ('\u{345}', '\u{345}'), ('\u{370}', '\u{374}'), ('\u{376}', '\u{377}'), - ('\u{37a}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', - '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), - ('\u{3f7}', '\u{481}'), ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}', - '\u{559}'), ('\u{561}', '\u{587}'), ('\u{5b0}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), - ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), ('\u{5d0}', - '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{610}', '\u{61a}'), ('\u{620}', '\u{657}'), - ('\u{659}', '\u{65f}'), ('\u{66e}', '\u{6d3}'), ('\u{6d5}', '\u{6dc}'), ('\u{6e1}', - '\u{6e8}'), ('\u{6ed}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), - ('\u{710}', '\u{73f}'), ('\u{74d}', '\u{7b1}'), ('\u{7ca}', '\u{7ea}'), ('\u{7f4}', - '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{800}', '\u{817}'), ('\u{81a}', '\u{82c}'), - ('\u{840}', '\u{858}'), ('\u{8a0}', '\u{8b4}'), ('\u{8e3}', '\u{8e9}'), ('\u{8f0}', - '\u{93b}'), ('\u{93d}', '\u{94c}'), ('\u{94e}', '\u{950}'), ('\u{955}', '\u{963}'), - ('\u{971}', '\u{983}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', - '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), - ('\u{9bd}', '\u{9c4}'), ('\u{9c7}', '\u{9c8}'), ('\u{9cb}', '\u{9cc}'), ('\u{9ce}', - '\u{9ce}'), ('\u{9d7}', '\u{9d7}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e3}'), - ('\u{9f0}', '\u{9f1}'), ('\u{a01}', '\u{a03}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', - '\u{a10}'), ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), - ('\u{a35}', '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a3e}', '\u{a42}'), ('\u{a47}', - '\u{a48}'), ('\u{a4b}', '\u{a4c}'), ('\u{a51}', '\u{a51}'), ('\u{a59}', '\u{a5c}'), - ('\u{a5e}', '\u{a5e}'), ('\u{a70}', '\u{a75}'), ('\u{a81}', '\u{a83}'), ('\u{a85}', - '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), - ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abd}', '\u{ac5}'), ('\u{ac7}', - '\u{ac9}'), ('\u{acb}', '\u{acc}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae3}'), - ('\u{af9}', '\u{af9}'), ('\u{b01}', '\u{b03}'), ('\u{b05}', '\u{b0c}'), ('\u{b0f}', - '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}', '\u{b33}'), - ('\u{b35}', '\u{b39}'), ('\u{b3d}', '\u{b44}'), ('\u{b47}', '\u{b48}'), ('\u{b4b}', - '\u{b4c}'), ('\u{b56}', '\u{b57}'), ('\u{b5c}', '\u{b5d}'), ('\u{b5f}', '\u{b63}'), - ('\u{b71}', '\u{b71}'), ('\u{b82}', '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', - '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), - ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', - '\u{bb9}'), ('\u{bbe}', '\u{bc2}'), ('\u{bc6}', '\u{bc8}'), ('\u{bca}', '\u{bcc}'), - ('\u{bd0}', '\u{bd0}'), ('\u{bd7}', '\u{bd7}'), ('\u{c00}', '\u{c03}'), ('\u{c05}', - '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), - ('\u{c3d}', '\u{c44}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4c}'), ('\u{c55}', - '\u{c56}'), ('\u{c58}', '\u{c5a}'), ('\u{c60}', '\u{c63}'), ('\u{c81}', '\u{c83}'), - ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', - '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbd}', '\u{cc4}'), ('\u{cc6}', '\u{cc8}'), - ('\u{cca}', '\u{ccc}'), ('\u{cd5}', '\u{cd6}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', - '\u{ce3}'), ('\u{cf1}', '\u{cf2}'), ('\u{d01}', '\u{d03}'), ('\u{d05}', '\u{d0c}'), - ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d44}'), ('\u{d46}', - '\u{d48}'), ('\u{d4a}', '\u{d4c}'), ('\u{d4e}', '\u{d4e}'), ('\u{d57}', '\u{d57}'), - ('\u{d5f}', '\u{d63}'), ('\u{d7a}', '\u{d7f}'), ('\u{d82}', '\u{d83}'), ('\u{d85}', - '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), - ('\u{dc0}', '\u{dc6}'), ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('\u{dd8}', - '\u{ddf}'), ('\u{df2}', '\u{df3}'), ('\u{e01}', '\u{e3a}'), ('\u{e40}', '\u{e46}'), - ('\u{e4d}', '\u{e4d}'), ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', - '\u{e88}'), ('\u{e8a}', '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), - ('\u{e99}', '\u{e9f}'), ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', - '\u{ea7}'), ('\u{eaa}', '\u{eab}'), ('\u{ead}', '\u{eb9}'), ('\u{ebb}', '\u{ebd}'), - ('\u{ec0}', '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), ('\u{ecd}', '\u{ecd}'), ('\u{edc}', - '\u{edf}'), ('\u{f00}', '\u{f00}'), ('\u{f40}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), - ('\u{f71}', '\u{f81}'), ('\u{f88}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{1000}', - '\u{1036}'), ('\u{1038}', '\u{1038}'), ('\u{103b}', '\u{103f}'), ('\u{1050}', '\u{1062}'), - ('\u{1065}', '\u{1068}'), ('\u{106e}', '\u{1086}'), ('\u{108e}', '\u{108e}'), ('\u{109c}', - '\u{109d}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), - ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', - '\u{1256}'), ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), - ('\u{128a}', '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', - '\u{12be}'), ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), - ('\u{12d8}', '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{135f}', - '\u{135f}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f5}'), ('\u{13f8}', '\u{13fd}'), - ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', - '\u{16ea}'), ('\u{16ee}', '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1713}'), - ('\u{1720}', '\u{1733}'), ('\u{1740}', '\u{1753}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', - '\u{1770}'), ('\u{1772}', '\u{1773}'), ('\u{1780}', '\u{17b3}'), ('\u{17b6}', '\u{17c8}'), - ('\u{17d7}', '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}', '\u{1877}'), ('\u{1880}', - '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1920}', '\u{192b}'), - ('\u{1930}', '\u{1938}'), ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}'), ('\u{1980}', - '\u{19ab}'), ('\u{19b0}', '\u{19c9}'), ('\u{1a00}', '\u{1a1b}'), ('\u{1a20}', '\u{1a5e}'), - ('\u{1a61}', '\u{1a74}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1b00}', '\u{1b33}'), ('\u{1b35}', - '\u{1b43}'), ('\u{1b45}', '\u{1b4b}'), ('\u{1b80}', '\u{1ba9}'), ('\u{1bac}', '\u{1baf}'), - ('\u{1bba}', '\u{1be5}'), ('\u{1be7}', '\u{1bf1}'), ('\u{1c00}', '\u{1c35}'), ('\u{1c4d}', - '\u{1c4f}'), ('\u{1c5a}', '\u{1c7d}'), ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}', '\u{1cf3}'), - ('\u{1cf5}', '\u{1cf6}'), ('\u{1d00}', '\u{1dbf}'), ('\u{1de7}', '\u{1df4}'), ('\u{1e00}', - '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), - ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', - '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), - ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', - '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), - ('\u{1ff6}', '\u{1ffc}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', - '\u{209c}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), - ('\u{2115}', '\u{2115}'), ('\u{2119}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', - '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{212d}'), ('\u{212f}', '\u{2139}'), - ('\u{213c}', '\u{213f}'), ('\u{2145}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', - '\u{2188}'), ('\u{24b6}', '\u{24e9}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), - ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}', '\u{2cf3}'), ('\u{2d00}', - '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), - ('\u{2d6f}', '\u{2d6f}'), ('\u{2d80}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', - '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), - ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{2de0}', - '\u{2dff}'), ('\u{2e2f}', '\u{2e2f}'), ('\u{3005}', '\u{3007}'), ('\u{3021}', '\u{3029}'), - ('\u{3031}', '\u{3035}'), ('\u{3038}', '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{309d}', - '\u{309f}'), ('\u{30a1}', '\u{30fa}'), ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), - ('\u{3131}', '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', - '\u{4db5}'), ('\u{4e00}', '\u{9fd5}'), ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), - ('\u{a500}', '\u{a60c}'), ('\u{a610}', '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a640}', - '\u{a66e}'), ('\u{a674}', '\u{a67b}'), ('\u{a67f}', '\u{a6ef}'), ('\u{a717}', '\u{a71f}'), - ('\u{a722}', '\u{a788}'), ('\u{a78b}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b7}'), ('\u{a7f7}', - '\u{a801}'), ('\u{a803}', '\u{a805}'), ('\u{a807}', '\u{a80a}'), ('\u{a80c}', '\u{a827}'), - ('\u{a840}', '\u{a873}'), ('\u{a880}', '\u{a8c3}'), ('\u{a8f2}', '\u{a8f7}'), ('\u{a8fb}', - '\u{a8fb}'), ('\u{a8fd}', '\u{a8fd}'), ('\u{a90a}', '\u{a92a}'), ('\u{a930}', '\u{a952}'), - ('\u{a960}', '\u{a97c}'), ('\u{a980}', '\u{a9b2}'), ('\u{a9b4}', '\u{a9bf}'), ('\u{a9cf}', - '\u{a9cf}'), ('\u{a9e0}', '\u{a9e4}'), ('\u{a9e6}', '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), - ('\u{aa00}', '\u{aa36}'), ('\u{aa40}', '\u{aa4d}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', - '\u{aa7a}'), ('\u{aa7e}', '\u{aabe}'), ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), - ('\u{aadb}', '\u{aadd}'), ('\u{aae0}', '\u{aaef}'), ('\u{aaf2}', '\u{aaf5}'), ('\u{ab01}', - '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), - ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab65}'), ('\u{ab70}', - '\u{abea}'), ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), - ('\u{f900}', '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', - '\u{fb17}'), ('\u{fb1d}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), - ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', - '\u{fbb1}'), ('\u{fbd3}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), - ('\u{fdf0}', '\u{fdfb}'), ('\u{fe70}', '\u{fe74}'), ('\u{fe76}', '\u{fefc}'), ('\u{ff21}', - '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', '\u{ffbe}'), ('\u{ffc2}', '\u{ffc7}'), - ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), ('\u{10000}', - '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), ('\u{1003c}', - '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), ('\u{10080}', - '\u{100fa}'), ('\u{10140}', '\u{10174}'), ('\u{10280}', '\u{1029c}'), ('\u{102a0}', - '\u{102d0}'), ('\u{10300}', '\u{1031f}'), ('\u{10330}', '\u{1034a}'), ('\u{10350}', - '\u{1037a}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', - '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), ('\u{10400}', '\u{1049d}'), ('\u{10500}', - '\u{10527}'), ('\u{10530}', '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', - '\u{10755}'), ('\u{10760}', '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', - '\u{10808}'), ('\u{1080a}', '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', - '\u{1083c}'), ('\u{1083f}', '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', - '\u{1089e}'), ('\u{108e0}', '\u{108f2}'), ('\u{108f4}', '\u{108f5}'), ('\u{10900}', - '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}', - '\u{109bf}'), ('\u{10a00}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', - '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), ('\u{10a19}', '\u{10a33}'), ('\u{10a60}', - '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', - '\u{10ae4}'), ('\u{10b00}', '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', - '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), ('\u{10c80}', - '\u{10cb2}'), ('\u{10cc0}', '\u{10cf2}'), ('\u{11000}', '\u{11045}'), ('\u{11082}', - '\u{110b8}'), ('\u{110d0}', '\u{110e8}'), ('\u{11100}', '\u{11132}'), ('\u{11150}', - '\u{11172}'), ('\u{11176}', '\u{11176}'), ('\u{11180}', '\u{111bf}'), ('\u{111c1}', - '\u{111c4}'), ('\u{111da}', '\u{111da}'), ('\u{111dc}', '\u{111dc}'), ('\u{11200}', - '\u{11211}'), ('\u{11213}', '\u{11234}'), ('\u{11237}', '\u{11237}'), ('\u{11280}', - '\u{11286}'), ('\u{11288}', '\u{11288}'), ('\u{1128a}', '\u{1128d}'), ('\u{1128f}', - '\u{1129d}'), ('\u{1129f}', '\u{112a8}'), ('\u{112b0}', '\u{112e8}'), ('\u{11300}', - '\u{11303}'), ('\u{11305}', '\u{1130c}'), ('\u{1130f}', '\u{11310}'), ('\u{11313}', - '\u{11328}'), ('\u{1132a}', '\u{11330}'), ('\u{11332}', '\u{11333}'), ('\u{11335}', - '\u{11339}'), ('\u{1133d}', '\u{11344}'), ('\u{11347}', '\u{11348}'), ('\u{1134b}', - '\u{1134c}'), ('\u{11350}', '\u{11350}'), ('\u{11357}', '\u{11357}'), ('\u{1135d}', - '\u{11363}'), ('\u{11480}', '\u{114c1}'), ('\u{114c4}', '\u{114c5}'), ('\u{114c7}', - '\u{114c7}'), ('\u{11580}', '\u{115b5}'), ('\u{115b8}', '\u{115be}'), ('\u{115d8}', - '\u{115dd}'), ('\u{11600}', '\u{1163e}'), ('\u{11640}', '\u{11640}'), ('\u{11644}', - '\u{11644}'), ('\u{11680}', '\u{116b5}'), ('\u{11700}', '\u{11719}'), ('\u{1171d}', - '\u{1172a}'), ('\u{118a0}', '\u{118df}'), ('\u{118ff}', '\u{118ff}'), ('\u{11ac0}', - '\u{11af8}'), ('\u{12000}', '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}', - '\u{12543}'), ('\u{13000}', '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}', - '\u{16a38}'), ('\u{16a40}', '\u{16a5e}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16b00}', - '\u{16b36}'), ('\u{16b40}', '\u{16b43}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', - '\u{16b8f}'), ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f7e}'), ('\u{16f93}', - '\u{16f9f}'), ('\u{1b000}', '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', - '\u{1bc7c}'), ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1bc9e}', - '\u{1bc9e}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', - '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', - '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', - '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', - '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', - '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', - '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', - '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', - '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', - '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', - '\u{1d7cb}'), ('\u{1e800}', '\u{1e8c4}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', - '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', - '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', - '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', - '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', - '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', - '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', - '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', - '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', - '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', - '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', - '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{1f130}', '\u{1f149}'), ('\u{1f150}', - '\u{1f169}'), ('\u{1f170}', '\u{1f189}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', - '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2b820}', '\u{2cea1}'), ('\u{2f800}', - '\u{2fa1d}') - ]; + pub const Alphabetic_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, + 0x0000000000000000, 0xbcdf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbfff0000000000ff, 0x000707ffffff00b6, + 0xffffffff07ff0000, 0xffffc000feffffff, 0xffffffffffffffff, 0x9c00e1fe1fefffff, + 0xffffffffffff0000, 0xffffffffffffe000, 0x0003ffffffffffff, 0x043007fffffffc00 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 36, 36, 36, 36, 36, 36, 36, 36, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 31, 63, 64, 65, 66, 55, 67, 31, 68, 36, 36, 36, 69, 36, 36, 36, 36, 70, + 71, 72, 73, 31, 74, 75, 31, 76, 77, 78, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 79, + 80, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 81, 82, 36, 83, 84, 85, 86, 87, 88, 31, 31, 31, 31, 31, 31, + 31, 89, 44, 90, 91, 92, 36, 93, 94, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 55, 31, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, 103, 104, + 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 117, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 118, 119, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, 36, + 36, 36, 120, 36, 121, 122, 123, 124, 125, 36, 36, 36, 36, 126, 127, 128, 129, 31, 130, + 36, 131, 132, 133, 113, 134 + ], + r3: &[ + 0x00001ffffcffffff, 0x0000000001ffffff, 0x001fffff00000000, 0xffff03f800000000, + 0xefffffffffffffff, 0xfffe000fffe1dfff, 0xe3c5fdfffff99fef, 0x0003000fb080599f, + 0xc36dfdfffff987ee, 0x003f00005e021987, 0xe3edfdfffffbbfee, 0x0200000f00011bbf, + 0xe3edfdfffff99fee, 0x0002000fb0c0199f, 0xc3ffc718d63dc7ec, 0x0000000000811dc7, + 0xe3fffdfffffddfef, 0x0000000f07601ddf, 0xe3effdfffffddfee, 0x0006000f40601ddf, + 0xe7fffffffffddfee, 0xfc00000f80805ddf, 0x2ffbfffffc7fffec, 0x000c0000ff5f807f, + 0x07fffffffffffffe, 0x000000000000207f, 0x3bffecaefef02596, 0x00000000f000205f, + 0x0000000000000001, 0xfffe1ffffffffeff, 0x1ffffffffeffff03, 0x0000000000000000, + 0xf97fffffffffffff, 0xffffc1e7ffff0000, 0xffffffff3000407f, 0xf7ffffffffff20bf, + 0xffffffffffffffff, 0xffffffff3d7f3dff, 0x7f3dffffffff3dff, 0xffffffffff7fff3d, + 0xffffffffff3dffff, 0x0000000087ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, + 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, + 0x000fffff000fdfff, 0x000ddfff000fffff, 0xffcfffffffffffff, 0x00000000108001ff, + 0xffffffff00000000, 0x00ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, + 0x01ff0fff7fffffff, 0x001f3fffffff0000, 0xffff0fffffffffff, 0x00000000000003ff, + 0xffffffff0fffffff, 0x001ffffe7fffffff, 0x0000008000000000, 0xffefffffffffffff, + 0x0000000000000fef, 0xfc00f3ffffffffff, 0x0003ffbfffffffff, 0x3ffffffffc00e000, + 0x006fde0000000000, 0x001fff8000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, + 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, + 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0x00000000000001ff, 0xffc0000000000000, + 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, + 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, + 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, + 0xfffe3fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, + 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x8ff07fffffffffff, + 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff3ffffffff9ff, 0xff80000000000000, + 0x000000fffffff7bb, 0x000fffffffffffff, 0x28fc00000000000f, 0xffff07fffffffc00, + 0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x7c00ffdf00008000, 0x007fffffffffffff, + 0xc47fffff00003fff, 0x7fffffffffffffff, 0x003cffff38000005, 0xffff7f7f007e7e7e, + 0xffff003ff7ffffff, 0x000007ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, + 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, + 0x0003ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, + 0xfffffffffffcffff, 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, + 0x07fffffe00000000, 0xffffffc007fffffe, 0x000000001cfcfcfc + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, + 14, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + ], + r5: &[ + 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 4, 13, 14, 4, 4, 2, 2, 2, 2, + 15, 16, 4, 4, 17, 18, 19, 20, 21, 4, 22, 4, 23, 24, 25, 26, 27, 28, 29, 4, 2, 30, 31, + 31, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 32, 33, 34, 31, 35, 2, 36, 37, 4, 38, 39, 40, + 41, 4, 4, 4, 4, 2, 42, 4, 4, 43, 44, 45, 46, 27, 4, 47, 4, 4, 4, 4, 4, 48, 49, 4, 4, 4, + 4, 4, 4, 4, 50, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 52, 2, 2, 2, 53, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 52, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 54, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, + 2, 2, 2, 50, 19, 4, 55, 15, 56, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 58, 59, 4, + 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 61, 62, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 63, 64, 65, 66, 67, + 2, 2, 2, 2, 68, 69, 70, 71, 72, 73, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 74, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 75, 76, 77, 4, 4, 4, 4, 4, 4, 4, 4, 4, 78, 79, + 80, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 81, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 82, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4 + ], + r6: &[ + 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, + 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, + 0xffff0000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, + 0x000000003fffffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, + 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, + 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, 0x000ffffffeeff06f, + 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, 0x003fffffffffffff, + 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, 0x0007ffffffffffff, + 0x000000000000003f, 0x01fffffffffffffc, 0x000001ffffff0000, 0x0047ffffffff0000, + 0x000000001400001e, 0x009ffffffffbffff, 0xffff01ffbfffbd7f, 0x000001ffffffffff, + 0xe3edfdfffff99fef, 0x0000000fe081199f, 0x00000000000000b3, 0x7f3fffffffffffff, + 0x000000003f000000, 0x7fffffffffffffff, 0x0000000000000011, 0x000007ffe3ffffff, + 0xffffffff00000000, 0x80000000ffffffff, 0x01ffffffffffffff, 0x0000000003ffffff, + 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x00003fffffff0000, + 0xe0fffff80000000f, 0x000000000000ffff, 0x7fffffffffff001f, 0x00000000fff80000, + 0x0000000000000003, 0x1fff07ffffffffff, 0x0000000043ff01ff, 0xffffffffffdfffff, + 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, + 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, + 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef, + 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0xffff000000000000, 0xffff03ffffff03ff, + 0x00000000000003ff, 0x00000000007fffff, 0x00000003ffffffff + ], + }; pub fn Alphabetic(c: char) -> bool { - super::bsearch_range_table(c, Alphabetic_table) + super::trie_lookup_range_table(c, Alphabetic_table) } - pub const Case_Ignorable_table: &'static [(char, char)] = &[ - ('\u{27}', '\u{27}'), ('\u{2e}', '\u{2e}'), ('\u{3a}', '\u{3a}'), ('\u{5e}', '\u{5e}'), - ('\u{60}', '\u{60}'), ('\u{a8}', '\u{a8}'), ('\u{ad}', '\u{ad}'), ('\u{af}', '\u{af}'), - ('\u{b4}', '\u{b4}'), ('\u{b7}', '\u{b8}'), ('\u{2b0}', '\u{36f}'), ('\u{374}', '\u{375}'), - ('\u{37a}', '\u{37a}'), ('\u{384}', '\u{385}'), ('\u{387}', '\u{387}'), ('\u{483}', - '\u{489}'), ('\u{559}', '\u{559}'), ('\u{591}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), - ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), ('\u{5f4}', - '\u{5f4}'), ('\u{600}', '\u{605}'), ('\u{610}', '\u{61a}'), ('\u{61c}', '\u{61c}'), - ('\u{640}', '\u{640}'), ('\u{64b}', '\u{65f}'), ('\u{670}', '\u{670}'), ('\u{6d6}', - '\u{6dd}'), ('\u{6df}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), ('\u{70f}', '\u{70f}'), - ('\u{711}', '\u{711}'), ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', - '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{816}', '\u{82d}'), ('\u{859}', '\u{85b}'), - ('\u{8e3}', '\u{902}'), ('\u{93a}', '\u{93a}'), ('\u{93c}', '\u{93c}'), ('\u{941}', - '\u{948}'), ('\u{94d}', '\u{94d}'), ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), - ('\u{971}', '\u{971}'), ('\u{981}', '\u{981}'), ('\u{9bc}', '\u{9bc}'), ('\u{9c1}', - '\u{9c4}'), ('\u{9cd}', '\u{9cd}'), ('\u{9e2}', '\u{9e3}'), ('\u{a01}', '\u{a02}'), - ('\u{a3c}', '\u{a3c}'), ('\u{a41}', '\u{a42}'), ('\u{a47}', '\u{a48}'), ('\u{a4b}', - '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), ('\u{a75}', '\u{a75}'), - ('\u{a81}', '\u{a82}'), ('\u{abc}', '\u{abc}'), ('\u{ac1}', '\u{ac5}'), ('\u{ac7}', - '\u{ac8}'), ('\u{acd}', '\u{acd}'), ('\u{ae2}', '\u{ae3}'), ('\u{b01}', '\u{b01}'), - ('\u{b3c}', '\u{b3c}'), ('\u{b3f}', '\u{b3f}'), ('\u{b41}', '\u{b44}'), ('\u{b4d}', - '\u{b4d}'), ('\u{b56}', '\u{b56}'), ('\u{b62}', '\u{b63}'), ('\u{b82}', '\u{b82}'), - ('\u{bc0}', '\u{bc0}'), ('\u{bcd}', '\u{bcd}'), ('\u{c00}', '\u{c00}'), ('\u{c3e}', - '\u{c40}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), - ('\u{c62}', '\u{c63}'), ('\u{c81}', '\u{c81}'), ('\u{cbc}', '\u{cbc}'), ('\u{cbf}', - '\u{cbf}'), ('\u{cc6}', '\u{cc6}'), ('\u{ccc}', '\u{ccd}'), ('\u{ce2}', '\u{ce3}'), - ('\u{d01}', '\u{d01}'), ('\u{d41}', '\u{d44}'), ('\u{d4d}', '\u{d4d}'), ('\u{d62}', - '\u{d63}'), ('\u{dca}', '\u{dca}'), ('\u{dd2}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), - ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), ('\u{e46}', '\u{e4e}'), ('\u{eb1}', - '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), ('\u{ebb}', '\u{ebc}'), ('\u{ec6}', '\u{ec6}'), - ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), ('\u{f35}', '\u{f35}'), ('\u{f37}', - '\u{f37}'), ('\u{f39}', '\u{f39}'), ('\u{f71}', '\u{f7e}'), ('\u{f80}', '\u{f84}'), - ('\u{f86}', '\u{f87}'), ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', - '\u{fc6}'), ('\u{102d}', '\u{1030}'), ('\u{1032}', '\u{1037}'), ('\u{1039}', '\u{103a}'), - ('\u{103d}', '\u{103e}'), ('\u{1058}', '\u{1059}'), ('\u{105e}', '\u{1060}'), ('\u{1071}', - '\u{1074}'), ('\u{1082}', '\u{1082}'), ('\u{1085}', '\u{1086}'), ('\u{108d}', '\u{108d}'), - ('\u{109d}', '\u{109d}'), ('\u{10fc}', '\u{10fc}'), ('\u{135d}', '\u{135f}'), ('\u{1712}', - '\u{1714}'), ('\u{1732}', '\u{1734}'), ('\u{1752}', '\u{1753}'), ('\u{1772}', '\u{1773}'), - ('\u{17b4}', '\u{17b5}'), ('\u{17b7}', '\u{17bd}'), ('\u{17c6}', '\u{17c6}'), ('\u{17c9}', - '\u{17d3}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dd}', '\u{17dd}'), ('\u{180b}', '\u{180e}'), - ('\u{1843}', '\u{1843}'), ('\u{18a9}', '\u{18a9}'), ('\u{1920}', '\u{1922}'), ('\u{1927}', - '\u{1928}'), ('\u{1932}', '\u{1932}'), ('\u{1939}', '\u{193b}'), ('\u{1a17}', '\u{1a18}'), - ('\u{1a1b}', '\u{1a1b}'), ('\u{1a56}', '\u{1a56}'), ('\u{1a58}', '\u{1a5e}'), ('\u{1a60}', - '\u{1a60}'), ('\u{1a62}', '\u{1a62}'), ('\u{1a65}', '\u{1a6c}'), ('\u{1a73}', '\u{1a7c}'), - ('\u{1a7f}', '\u{1a7f}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1ab0}', '\u{1abe}'), ('\u{1b00}', - '\u{1b03}'), ('\u{1b34}', '\u{1b34}'), ('\u{1b36}', '\u{1b3a}'), ('\u{1b3c}', '\u{1b3c}'), - ('\u{1b42}', '\u{1b42}'), ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '\u{1b81}'), ('\u{1ba2}', - '\u{1ba5}'), ('\u{1ba8}', '\u{1ba9}'), ('\u{1bab}', '\u{1bad}'), ('\u{1be6}', '\u{1be6}'), - ('\u{1be8}', '\u{1be9}'), ('\u{1bed}', '\u{1bed}'), ('\u{1bef}', '\u{1bf1}'), ('\u{1c2c}', - '\u{1c33}'), ('\u{1c36}', '\u{1c37}'), ('\u{1c78}', '\u{1c7d}'), ('\u{1cd0}', '\u{1cd2}'), - ('\u{1cd4}', '\u{1ce0}'), ('\u{1ce2}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), ('\u{1cf4}', - '\u{1cf4}'), ('\u{1cf8}', '\u{1cf9}'), ('\u{1d2c}', '\u{1d6a}'), ('\u{1d78}', '\u{1d78}'), - ('\u{1d9b}', '\u{1df5}'), ('\u{1dfc}', '\u{1dff}'), ('\u{1fbd}', '\u{1fbd}'), ('\u{1fbf}', - '\u{1fc1}'), ('\u{1fcd}', '\u{1fcf}'), ('\u{1fdd}', '\u{1fdf}'), ('\u{1fed}', '\u{1fef}'), - ('\u{1ffd}', '\u{1ffe}'), ('\u{200b}', '\u{200f}'), ('\u{2018}', '\u{2019}'), ('\u{2024}', - '\u{2024}'), ('\u{2027}', '\u{2027}'), ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{2064}'), - ('\u{2066}', '\u{206f}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', - '\u{209c}'), ('\u{20d0}', '\u{20f0}'), ('\u{2c7c}', '\u{2c7d}'), ('\u{2cef}', '\u{2cf1}'), - ('\u{2d6f}', '\u{2d6f}'), ('\u{2d7f}', '\u{2d7f}'), ('\u{2de0}', '\u{2dff}'), ('\u{2e2f}', - '\u{2e2f}'), ('\u{3005}', '\u{3005}'), ('\u{302a}', '\u{302d}'), ('\u{3031}', '\u{3035}'), - ('\u{303b}', '\u{303b}'), ('\u{3099}', '\u{309e}'), ('\u{30fc}', '\u{30fe}'), ('\u{a015}', - '\u{a015}'), ('\u{a4f8}', '\u{a4fd}'), ('\u{a60c}', '\u{a60c}'), ('\u{a66f}', '\u{a672}'), - ('\u{a674}', '\u{a67d}'), ('\u{a67f}', '\u{a67f}'), ('\u{a69c}', '\u{a69f}'), ('\u{a6f0}', - '\u{a6f1}'), ('\u{a700}', '\u{a721}'), ('\u{a770}', '\u{a770}'), ('\u{a788}', '\u{a78a}'), - ('\u{a7f8}', '\u{a7f9}'), ('\u{a802}', '\u{a802}'), ('\u{a806}', '\u{a806}'), ('\u{a80b}', - '\u{a80b}'), ('\u{a825}', '\u{a826}'), ('\u{a8c4}', '\u{a8c4}'), ('\u{a8e0}', '\u{a8f1}'), - ('\u{a926}', '\u{a92d}'), ('\u{a947}', '\u{a951}'), ('\u{a980}', '\u{a982}'), ('\u{a9b3}', - '\u{a9b3}'), ('\u{a9b6}', '\u{a9b9}'), ('\u{a9bc}', '\u{a9bc}'), ('\u{a9cf}', '\u{a9cf}'), - ('\u{a9e5}', '\u{a9e6}'), ('\u{aa29}', '\u{aa2e}'), ('\u{aa31}', '\u{aa32}'), ('\u{aa35}', - '\u{aa36}'), ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', '\u{aa4c}'), ('\u{aa70}', '\u{aa70}'), - ('\u{aa7c}', '\u{aa7c}'), ('\u{aab0}', '\u{aab0}'), ('\u{aab2}', '\u{aab4}'), ('\u{aab7}', - '\u{aab8}'), ('\u{aabe}', '\u{aabf}'), ('\u{aac1}', '\u{aac1}'), ('\u{aadd}', '\u{aadd}'), - ('\u{aaec}', '\u{aaed}'), ('\u{aaf3}', '\u{aaf4}'), ('\u{aaf6}', '\u{aaf6}'), ('\u{ab5b}', - '\u{ab5f}'), ('\u{abe5}', '\u{abe5}'), ('\u{abe8}', '\u{abe8}'), ('\u{abed}', '\u{abed}'), - ('\u{fb1e}', '\u{fb1e}'), ('\u{fbb2}', '\u{fbc1}'), ('\u{fe00}', '\u{fe0f}'), ('\u{fe13}', - '\u{fe13}'), ('\u{fe20}', '\u{fe2f}'), ('\u{fe52}', '\u{fe52}'), ('\u{fe55}', '\u{fe55}'), - ('\u{feff}', '\u{feff}'), ('\u{ff07}', '\u{ff07}'), ('\u{ff0e}', '\u{ff0e}'), ('\u{ff1a}', - '\u{ff1a}'), ('\u{ff3e}', '\u{ff3e}'), ('\u{ff40}', '\u{ff40}'), ('\u{ff70}', '\u{ff70}'), - ('\u{ff9e}', '\u{ff9f}'), ('\u{ffe3}', '\u{ffe3}'), ('\u{fff9}', '\u{fffb}'), ('\u{101fd}', - '\u{101fd}'), ('\u{102e0}', '\u{102e0}'), ('\u{10376}', '\u{1037a}'), ('\u{10a01}', - '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '\u{10a0f}'), ('\u{10a38}', - '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', '\u{10ae6}'), ('\u{11001}', - '\u{11001}'), ('\u{11038}', '\u{11046}'), ('\u{1107f}', '\u{11081}'), ('\u{110b3}', - '\u{110b6}'), ('\u{110b9}', '\u{110ba}'), ('\u{110bd}', '\u{110bd}'), ('\u{11100}', - '\u{11102}'), ('\u{11127}', '\u{1112b}'), ('\u{1112d}', '\u{11134}'), ('\u{11173}', - '\u{11173}'), ('\u{11180}', '\u{11181}'), ('\u{111b6}', '\u{111be}'), ('\u{111ca}', - '\u{111cc}'), ('\u{1122f}', '\u{11231}'), ('\u{11234}', '\u{11234}'), ('\u{11236}', - '\u{11237}'), ('\u{112df}', '\u{112df}'), ('\u{112e3}', '\u{112ea}'), ('\u{11300}', - '\u{11301}'), ('\u{1133c}', '\u{1133c}'), ('\u{11340}', '\u{11340}'), ('\u{11366}', - '\u{1136c}'), ('\u{11370}', '\u{11374}'), ('\u{114b3}', '\u{114b8}'), ('\u{114ba}', - '\u{114ba}'), ('\u{114bf}', '\u{114c0}'), ('\u{114c2}', '\u{114c3}'), ('\u{115b2}', - '\u{115b5}'), ('\u{115bc}', '\u{115bd}'), ('\u{115bf}', '\u{115c0}'), ('\u{115dc}', - '\u{115dd}'), ('\u{11633}', '\u{1163a}'), ('\u{1163d}', '\u{1163d}'), ('\u{1163f}', - '\u{11640}'), ('\u{116ab}', '\u{116ab}'), ('\u{116ad}', '\u{116ad}'), ('\u{116b0}', - '\u{116b5}'), ('\u{116b7}', '\u{116b7}'), ('\u{1171d}', '\u{1171f}'), ('\u{11722}', - '\u{11725}'), ('\u{11727}', '\u{1172b}'), ('\u{16af0}', '\u{16af4}'), ('\u{16b30}', - '\u{16b36}'), ('\u{16b40}', '\u{16b43}'), ('\u{16f8f}', '\u{16f9f}'), ('\u{1bc9d}', - '\u{1bc9e}'), ('\u{1bca0}', '\u{1bca3}'), ('\u{1d167}', '\u{1d169}'), ('\u{1d173}', - '\u{1d182}'), ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', - '\u{1d244}'), ('\u{1da00}', '\u{1da36}'), ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', - '\u{1da75}'), ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), ('\u{1daa1}', - '\u{1daaf}'), ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1f3fb}', '\u{1f3ff}'), ('\u{e0001}', - '\u{e0001}'), ('\u{e0020}', '\u{e007f}'), ('\u{e0100}', '\u{e01ef}') - ]; + pub const Case_Ignorable_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xffff000000000000, 0xffffffffffffffff, + 0xffffffffffffffff, 0x0430ffffffffffff, 0x00000000000000b0, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, + 0x0000000000000000, 0x0000000002000000, 0xbffffffffffe0000, 0x00100000000000b6, + 0x0000000017ff003f, 0x00010000fffff801, 0x0000000000000000, 0x00003dffbfc00000, + 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x043ff80000000000 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 38, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, 44, 45, 46, + 47, 48, 49, 2, 50, 51, 52, 53, 54, 2, 2, 2, 2, 2, 2, 55, 56, 57, 58, 59, 60, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 62, 2, 63, 2, 64, 65, 2, 2, 2, 2, 2, 2, 2, + 66, 2, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 49, 2, 2, 2, 2, 70, 71, 72, 73, 74, 75, 76, 77, 78, 2, 2, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 2, 88, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 94, 2, 95, 96, 97, + 98, 99 + ], + r3: &[ + 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffff800000000, + 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, + 0x1000000000000006, 0x0023000000023986, 0x0000000c000021be, 0x9000000000000002, + 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, + 0x0000000c00603dc1, 0x0000000c00003040, 0x0000000000000002, 0x00000000005c0400, + 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, 0x0000000000003f40, + 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, + 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x1000000000000000, + 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, + 0x00000000208ffe40, 0x0000000000007800, 0x0000000000000008, 0x0000020000000000, + 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff008000000000, + 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, + 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, 0xfffff00000000000, + 0x010007ffffffffff, 0xfffffffff8000000, 0xf03fffffffffffff, 0xa000000000000000, + 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, 0x000000001fff0000, + 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, 0x8000800000000000, + 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, 0x000000007e000000, + 0x7000000000000000, 0x0000000000200000, 0x0000000000001000, 0xbff7800000000000, + 0x00000000f0000000, 0x0003000000000000, 0x00000003ffffffff, 0x0001000000000000, + 0x0000000000000700, 0x0300000000000000, 0x0000006000000844, 0x0003ffff00000010, + 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, 0x0000006000008000, + 0x00667e0000000000, 0x1001000000001008, 0xc19d000000000000, 0x0058300020000002, + 0x00000000f8000000, 0x0000212000000000, 0x0000000040000000, 0xfffc000000000000, + 0x0000000000000003, 0x0000ffff0008ffff, 0x0000000000240000, 0x8000000000000000, + 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, 0x0e00000800000000 + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 0, 0, 17, 18, + 0, 0, 19, 20, 21, 22, 23, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, + 0, 0, 39, 39, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, + 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, + 0x2678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, + 0x0000000000001c00, 0x00d3800000000000, 0x000007f880000000, 0x1000000000000003, + 0x001f1fc000000001, 0x85f8000000000000, 0x000000000000000d, 0xb03c000000000000, + 0x0000000030000001, 0xa7f8000000000000, 0x0000000000000001, 0x00bf280000000000, + 0x00000fbce0000000, 0x001f000000000000, 0x007f000000000000, 0x000000000000000f, + 0x00000000ffff8000, 0x0000000f60000000, 0xfff8038000000000, 0x00003c0000000fe7, + 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, + 0x00000000007f0000, 0xf800000000000000, 0xffffffff00000002, 0xffffffffffffffff, + 0x0000ffffffffffff + ], + }; pub fn Case_Ignorable(c: char) -> bool { - super::bsearch_range_table(c, Case_Ignorable_table) + super::trie_lookup_range_table(c, Case_Ignorable_table) } - pub const Cased_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), - ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{1ba}'), - ('\u{1bc}', '\u{1bf}'), ('\u{1c4}', '\u{293}'), ('\u{295}', '\u{2b8}'), ('\u{2c0}', - '\u{2c1}'), ('\u{2e0}', '\u{2e4}'), ('\u{345}', '\u{345}'), ('\u{370}', '\u{373}'), - ('\u{376}', '\u{377}'), ('\u{37a}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}', - '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), - ('\u{3a3}', '\u{3f5}'), ('\u{3f7}', '\u{481}'), ('\u{48a}', '\u{52f}'), ('\u{531}', - '\u{556}'), ('\u{561}', '\u{587}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), - ('\u{10cd}', '\u{10cd}'), ('\u{13a0}', '\u{13f5}'), ('\u{13f8}', '\u{13fd}'), ('\u{1d00}', - '\u{1dbf}'), ('\u{1e00}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), - ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', - '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), - ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', - '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), - ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', - '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), - ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'), ('\u{2119}', '\u{211d}'), ('\u{2124}', - '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{212d}'), - ('\u{212f}', '\u{2134}'), ('\u{2139}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}', - '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{217f}'), ('\u{2183}', '\u{2184}'), - ('\u{24b6}', '\u{24e9}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', - '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), - ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{a640}', '\u{a66d}'), ('\u{a680}', - '\u{a69d}'), ('\u{a722}', '\u{a787}'), ('\u{a78b}', '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), - ('\u{a7b0}', '\u{a7b7}'), ('\u{a7f8}', '\u{a7fa}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', - '\u{ab65}'), ('\u{ab70}', '\u{abbf}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), - ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'), ('\u{10400}', '\u{1044f}'), - ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}', '\u{10cf2}'), ('\u{118a0}', '\u{118df}'), - ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), - ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), - ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), - ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), - ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), - ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), - ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), - ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), - ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), - ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), - ('\u{1f130}', '\u{1f149}'), ('\u{1f150}', '\u{1f169}'), ('\u{1f170}', '\u{1f189}') - ]; + pub const Cased_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xf7ffffffffffffff, 0xfffffffffffffff0, + 0xffffffffffffffff, 0xffffffffffffffff, 0x01ffffffffefffff, 0x0000001f00000003, + 0x0000000000000000, 0xbccf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe007fffff, 0x00000000000000ff, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, + 4, 5, 6, 7, 8, 0, 9, 10, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 4, + 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, 22, 4, 23, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 28, 29, 0, 0 + ], + r3: &[ + 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x3f3fffffffffffff, + 0xffffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, + 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf21fbd503e2ffc84, + 0xffffffff000043e0, 0x0000000000000018, 0xffc0000000000000, 0x000003ffffffffff, + 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, 0x000020bfffffffff, + 0x00003fffffffffff, 0x000000003fffffff, 0xfffffffc00000000, 0x00ff3fffffff78ff, + 0x0700000000000000, 0xffff000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, + 0x07fffffe00000000, 0x0000000007fffffe + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 6, 7, 8, 9, 10, 1, 1, 1, 1, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0xffffffffffffffff, 0x000000000000ffff, 0x0007ffffffffffff, + 0xffffffff00000000, 0x00000000ffffffff, 0xffffffffffdfffff, 0xebffde64dfffffff, + 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, + 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, + 0x0000000000000ff7, 0xffff000000000000, 0xffff03ffffff03ff, 0x00000000000003ff + ], + }; pub fn Cased(c: char) -> bool { - super::bsearch_range_table(c, Cased_table) + super::trie_lookup_range_table(c, Cased_table) } - pub const Lowercase_table: &'static [(char, char)] = &[ - ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), ('\u{ba}', '\u{ba}'), - ('\u{df}', '\u{f6}'), ('\u{f8}', '\u{ff}'), ('\u{101}', '\u{101}'), ('\u{103}', '\u{103}'), - ('\u{105}', '\u{105}'), ('\u{107}', '\u{107}'), ('\u{109}', '\u{109}'), ('\u{10b}', - '\u{10b}'), ('\u{10d}', '\u{10d}'), ('\u{10f}', '\u{10f}'), ('\u{111}', '\u{111}'), - ('\u{113}', '\u{113}'), ('\u{115}', '\u{115}'), ('\u{117}', '\u{117}'), ('\u{119}', - '\u{119}'), ('\u{11b}', '\u{11b}'), ('\u{11d}', '\u{11d}'), ('\u{11f}', '\u{11f}'), - ('\u{121}', '\u{121}'), ('\u{123}', '\u{123}'), ('\u{125}', '\u{125}'), ('\u{127}', - '\u{127}'), ('\u{129}', '\u{129}'), ('\u{12b}', '\u{12b}'), ('\u{12d}', '\u{12d}'), - ('\u{12f}', '\u{12f}'), ('\u{131}', '\u{131}'), ('\u{133}', '\u{133}'), ('\u{135}', - '\u{135}'), ('\u{137}', '\u{138}'), ('\u{13a}', '\u{13a}'), ('\u{13c}', '\u{13c}'), - ('\u{13e}', '\u{13e}'), ('\u{140}', '\u{140}'), ('\u{142}', '\u{142}'), ('\u{144}', - '\u{144}'), ('\u{146}', '\u{146}'), ('\u{148}', '\u{149}'), ('\u{14b}', '\u{14b}'), - ('\u{14d}', '\u{14d}'), ('\u{14f}', '\u{14f}'), ('\u{151}', '\u{151}'), ('\u{153}', - '\u{153}'), ('\u{155}', '\u{155}'), ('\u{157}', '\u{157}'), ('\u{159}', '\u{159}'), - ('\u{15b}', '\u{15b}'), ('\u{15d}', '\u{15d}'), ('\u{15f}', '\u{15f}'), ('\u{161}', - '\u{161}'), ('\u{163}', '\u{163}'), ('\u{165}', '\u{165}'), ('\u{167}', '\u{167}'), - ('\u{169}', '\u{169}'), ('\u{16b}', '\u{16b}'), ('\u{16d}', '\u{16d}'), ('\u{16f}', - '\u{16f}'), ('\u{171}', '\u{171}'), ('\u{173}', '\u{173}'), ('\u{175}', '\u{175}'), - ('\u{177}', '\u{177}'), ('\u{17a}', '\u{17a}'), ('\u{17c}', '\u{17c}'), ('\u{17e}', - '\u{180}'), ('\u{183}', '\u{183}'), ('\u{185}', '\u{185}'), ('\u{188}', '\u{188}'), - ('\u{18c}', '\u{18d}'), ('\u{192}', '\u{192}'), ('\u{195}', '\u{195}'), ('\u{199}', - '\u{19b}'), ('\u{19e}', '\u{19e}'), ('\u{1a1}', '\u{1a1}'), ('\u{1a3}', '\u{1a3}'), - ('\u{1a5}', '\u{1a5}'), ('\u{1a8}', '\u{1a8}'), ('\u{1aa}', '\u{1ab}'), ('\u{1ad}', - '\u{1ad}'), ('\u{1b0}', '\u{1b0}'), ('\u{1b4}', '\u{1b4}'), ('\u{1b6}', '\u{1b6}'), - ('\u{1b9}', '\u{1ba}'), ('\u{1bd}', '\u{1bf}'), ('\u{1c6}', '\u{1c6}'), ('\u{1c9}', - '\u{1c9}'), ('\u{1cc}', '\u{1cc}'), ('\u{1ce}', '\u{1ce}'), ('\u{1d0}', '\u{1d0}'), - ('\u{1d2}', '\u{1d2}'), ('\u{1d4}', '\u{1d4}'), ('\u{1d6}', '\u{1d6}'), ('\u{1d8}', - '\u{1d8}'), ('\u{1da}', '\u{1da}'), ('\u{1dc}', '\u{1dd}'), ('\u{1df}', '\u{1df}'), - ('\u{1e1}', '\u{1e1}'), ('\u{1e3}', '\u{1e3}'), ('\u{1e5}', '\u{1e5}'), ('\u{1e7}', - '\u{1e7}'), ('\u{1e9}', '\u{1e9}'), ('\u{1eb}', '\u{1eb}'), ('\u{1ed}', '\u{1ed}'), - ('\u{1ef}', '\u{1f0}'), ('\u{1f3}', '\u{1f3}'), ('\u{1f5}', '\u{1f5}'), ('\u{1f9}', - '\u{1f9}'), ('\u{1fb}', '\u{1fb}'), ('\u{1fd}', '\u{1fd}'), ('\u{1ff}', '\u{1ff}'), - ('\u{201}', '\u{201}'), ('\u{203}', '\u{203}'), ('\u{205}', '\u{205}'), ('\u{207}', - '\u{207}'), ('\u{209}', '\u{209}'), ('\u{20b}', '\u{20b}'), ('\u{20d}', '\u{20d}'), - ('\u{20f}', '\u{20f}'), ('\u{211}', '\u{211}'), ('\u{213}', '\u{213}'), ('\u{215}', - '\u{215}'), ('\u{217}', '\u{217}'), ('\u{219}', '\u{219}'), ('\u{21b}', '\u{21b}'), - ('\u{21d}', '\u{21d}'), ('\u{21f}', '\u{21f}'), ('\u{221}', '\u{221}'), ('\u{223}', - '\u{223}'), ('\u{225}', '\u{225}'), ('\u{227}', '\u{227}'), ('\u{229}', '\u{229}'), - ('\u{22b}', '\u{22b}'), ('\u{22d}', '\u{22d}'), ('\u{22f}', '\u{22f}'), ('\u{231}', - '\u{231}'), ('\u{233}', '\u{239}'), ('\u{23c}', '\u{23c}'), ('\u{23f}', '\u{240}'), - ('\u{242}', '\u{242}'), ('\u{247}', '\u{247}'), ('\u{249}', '\u{249}'), ('\u{24b}', - '\u{24b}'), ('\u{24d}', '\u{24d}'), ('\u{24f}', '\u{293}'), ('\u{295}', '\u{2b8}'), - ('\u{2c0}', '\u{2c1}'), ('\u{2e0}', '\u{2e4}'), ('\u{345}', '\u{345}'), ('\u{371}', - '\u{371}'), ('\u{373}', '\u{373}'), ('\u{377}', '\u{377}'), ('\u{37a}', '\u{37d}'), - ('\u{390}', '\u{390}'), ('\u{3ac}', '\u{3ce}'), ('\u{3d0}', '\u{3d1}'), ('\u{3d5}', - '\u{3d7}'), ('\u{3d9}', '\u{3d9}'), ('\u{3db}', '\u{3db}'), ('\u{3dd}', '\u{3dd}'), - ('\u{3df}', '\u{3df}'), ('\u{3e1}', '\u{3e1}'), ('\u{3e3}', '\u{3e3}'), ('\u{3e5}', - '\u{3e5}'), ('\u{3e7}', '\u{3e7}'), ('\u{3e9}', '\u{3e9}'), ('\u{3eb}', '\u{3eb}'), - ('\u{3ed}', '\u{3ed}'), ('\u{3ef}', '\u{3f3}'), ('\u{3f5}', '\u{3f5}'), ('\u{3f8}', - '\u{3f8}'), ('\u{3fb}', '\u{3fc}'), ('\u{430}', '\u{45f}'), ('\u{461}', '\u{461}'), - ('\u{463}', '\u{463}'), ('\u{465}', '\u{465}'), ('\u{467}', '\u{467}'), ('\u{469}', - '\u{469}'), ('\u{46b}', '\u{46b}'), ('\u{46d}', '\u{46d}'), ('\u{46f}', '\u{46f}'), - ('\u{471}', '\u{471}'), ('\u{473}', '\u{473}'), ('\u{475}', '\u{475}'), ('\u{477}', - '\u{477}'), ('\u{479}', '\u{479}'), ('\u{47b}', '\u{47b}'), ('\u{47d}', '\u{47d}'), - ('\u{47f}', '\u{47f}'), ('\u{481}', '\u{481}'), ('\u{48b}', '\u{48b}'), ('\u{48d}', - '\u{48d}'), ('\u{48f}', '\u{48f}'), ('\u{491}', '\u{491}'), ('\u{493}', '\u{493}'), - ('\u{495}', '\u{495}'), ('\u{497}', '\u{497}'), ('\u{499}', '\u{499}'), ('\u{49b}', - '\u{49b}'), ('\u{49d}', '\u{49d}'), ('\u{49f}', '\u{49f}'), ('\u{4a1}', '\u{4a1}'), - ('\u{4a3}', '\u{4a3}'), ('\u{4a5}', '\u{4a5}'), ('\u{4a7}', '\u{4a7}'), ('\u{4a9}', - '\u{4a9}'), ('\u{4ab}', '\u{4ab}'), ('\u{4ad}', '\u{4ad}'), ('\u{4af}', '\u{4af}'), - ('\u{4b1}', '\u{4b1}'), ('\u{4b3}', '\u{4b3}'), ('\u{4b5}', '\u{4b5}'), ('\u{4b7}', - '\u{4b7}'), ('\u{4b9}', '\u{4b9}'), ('\u{4bb}', '\u{4bb}'), ('\u{4bd}', '\u{4bd}'), - ('\u{4bf}', '\u{4bf}'), ('\u{4c2}', '\u{4c2}'), ('\u{4c4}', '\u{4c4}'), ('\u{4c6}', - '\u{4c6}'), ('\u{4c8}', '\u{4c8}'), ('\u{4ca}', '\u{4ca}'), ('\u{4cc}', '\u{4cc}'), - ('\u{4ce}', '\u{4cf}'), ('\u{4d1}', '\u{4d1}'), ('\u{4d3}', '\u{4d3}'), ('\u{4d5}', - '\u{4d5}'), ('\u{4d7}', '\u{4d7}'), ('\u{4d9}', '\u{4d9}'), ('\u{4db}', '\u{4db}'), - ('\u{4dd}', '\u{4dd}'), ('\u{4df}', '\u{4df}'), ('\u{4e1}', '\u{4e1}'), ('\u{4e3}', - '\u{4e3}'), ('\u{4e5}', '\u{4e5}'), ('\u{4e7}', '\u{4e7}'), ('\u{4e9}', '\u{4e9}'), - ('\u{4eb}', '\u{4eb}'), ('\u{4ed}', '\u{4ed}'), ('\u{4ef}', '\u{4ef}'), ('\u{4f1}', - '\u{4f1}'), ('\u{4f3}', '\u{4f3}'), ('\u{4f5}', '\u{4f5}'), ('\u{4f7}', '\u{4f7}'), - ('\u{4f9}', '\u{4f9}'), ('\u{4fb}', '\u{4fb}'), ('\u{4fd}', '\u{4fd}'), ('\u{4ff}', - '\u{4ff}'), ('\u{501}', '\u{501}'), ('\u{503}', '\u{503}'), ('\u{505}', '\u{505}'), - ('\u{507}', '\u{507}'), ('\u{509}', '\u{509}'), ('\u{50b}', '\u{50b}'), ('\u{50d}', - '\u{50d}'), ('\u{50f}', '\u{50f}'), ('\u{511}', '\u{511}'), ('\u{513}', '\u{513}'), - ('\u{515}', '\u{515}'), ('\u{517}', '\u{517}'), ('\u{519}', '\u{519}'), ('\u{51b}', - '\u{51b}'), ('\u{51d}', '\u{51d}'), ('\u{51f}', '\u{51f}'), ('\u{521}', '\u{521}'), - ('\u{523}', '\u{523}'), ('\u{525}', '\u{525}'), ('\u{527}', '\u{527}'), ('\u{529}', - '\u{529}'), ('\u{52b}', '\u{52b}'), ('\u{52d}', '\u{52d}'), ('\u{52f}', '\u{52f}'), - ('\u{561}', '\u{587}'), ('\u{13f8}', '\u{13fd}'), ('\u{1d00}', '\u{1dbf}'), ('\u{1e01}', - '\u{1e01}'), ('\u{1e03}', '\u{1e03}'), ('\u{1e05}', '\u{1e05}'), ('\u{1e07}', '\u{1e07}'), - ('\u{1e09}', '\u{1e09}'), ('\u{1e0b}', '\u{1e0b}'), ('\u{1e0d}', '\u{1e0d}'), ('\u{1e0f}', - '\u{1e0f}'), ('\u{1e11}', '\u{1e11}'), ('\u{1e13}', '\u{1e13}'), ('\u{1e15}', '\u{1e15}'), - ('\u{1e17}', '\u{1e17}'), ('\u{1e19}', '\u{1e19}'), ('\u{1e1b}', '\u{1e1b}'), ('\u{1e1d}', - '\u{1e1d}'), ('\u{1e1f}', '\u{1e1f}'), ('\u{1e21}', '\u{1e21}'), ('\u{1e23}', '\u{1e23}'), - ('\u{1e25}', '\u{1e25}'), ('\u{1e27}', '\u{1e27}'), ('\u{1e29}', '\u{1e29}'), ('\u{1e2b}', - '\u{1e2b}'), ('\u{1e2d}', '\u{1e2d}'), ('\u{1e2f}', '\u{1e2f}'), ('\u{1e31}', '\u{1e31}'), - ('\u{1e33}', '\u{1e33}'), ('\u{1e35}', '\u{1e35}'), ('\u{1e37}', '\u{1e37}'), ('\u{1e39}', - '\u{1e39}'), ('\u{1e3b}', '\u{1e3b}'), ('\u{1e3d}', '\u{1e3d}'), ('\u{1e3f}', '\u{1e3f}'), - ('\u{1e41}', '\u{1e41}'), ('\u{1e43}', '\u{1e43}'), ('\u{1e45}', '\u{1e45}'), ('\u{1e47}', - '\u{1e47}'), ('\u{1e49}', '\u{1e49}'), ('\u{1e4b}', '\u{1e4b}'), ('\u{1e4d}', '\u{1e4d}'), - ('\u{1e4f}', '\u{1e4f}'), ('\u{1e51}', '\u{1e51}'), ('\u{1e53}', '\u{1e53}'), ('\u{1e55}', - '\u{1e55}'), ('\u{1e57}', '\u{1e57}'), ('\u{1e59}', '\u{1e59}'), ('\u{1e5b}', '\u{1e5b}'), - ('\u{1e5d}', '\u{1e5d}'), ('\u{1e5f}', '\u{1e5f}'), ('\u{1e61}', '\u{1e61}'), ('\u{1e63}', - '\u{1e63}'), ('\u{1e65}', '\u{1e65}'), ('\u{1e67}', '\u{1e67}'), ('\u{1e69}', '\u{1e69}'), - ('\u{1e6b}', '\u{1e6b}'), ('\u{1e6d}', '\u{1e6d}'), ('\u{1e6f}', '\u{1e6f}'), ('\u{1e71}', - '\u{1e71}'), ('\u{1e73}', '\u{1e73}'), ('\u{1e75}', '\u{1e75}'), ('\u{1e77}', '\u{1e77}'), - ('\u{1e79}', '\u{1e79}'), ('\u{1e7b}', '\u{1e7b}'), ('\u{1e7d}', '\u{1e7d}'), ('\u{1e7f}', - '\u{1e7f}'), ('\u{1e81}', '\u{1e81}'), ('\u{1e83}', '\u{1e83}'), ('\u{1e85}', '\u{1e85}'), - ('\u{1e87}', '\u{1e87}'), ('\u{1e89}', '\u{1e89}'), ('\u{1e8b}', '\u{1e8b}'), ('\u{1e8d}', - '\u{1e8d}'), ('\u{1e8f}', '\u{1e8f}'), ('\u{1e91}', '\u{1e91}'), ('\u{1e93}', '\u{1e93}'), - ('\u{1e95}', '\u{1e9d}'), ('\u{1e9f}', '\u{1e9f}'), ('\u{1ea1}', '\u{1ea1}'), ('\u{1ea3}', - '\u{1ea3}'), ('\u{1ea5}', '\u{1ea5}'), ('\u{1ea7}', '\u{1ea7}'), ('\u{1ea9}', '\u{1ea9}'), - ('\u{1eab}', '\u{1eab}'), ('\u{1ead}', '\u{1ead}'), ('\u{1eaf}', '\u{1eaf}'), ('\u{1eb1}', - '\u{1eb1}'), ('\u{1eb3}', '\u{1eb3}'), ('\u{1eb5}', '\u{1eb5}'), ('\u{1eb7}', '\u{1eb7}'), - ('\u{1eb9}', '\u{1eb9}'), ('\u{1ebb}', '\u{1ebb}'), ('\u{1ebd}', '\u{1ebd}'), ('\u{1ebf}', - '\u{1ebf}'), ('\u{1ec1}', '\u{1ec1}'), ('\u{1ec3}', '\u{1ec3}'), ('\u{1ec5}', '\u{1ec5}'), - ('\u{1ec7}', '\u{1ec7}'), ('\u{1ec9}', '\u{1ec9}'), ('\u{1ecb}', '\u{1ecb}'), ('\u{1ecd}', - '\u{1ecd}'), ('\u{1ecf}', '\u{1ecf}'), ('\u{1ed1}', '\u{1ed1}'), ('\u{1ed3}', '\u{1ed3}'), - ('\u{1ed5}', '\u{1ed5}'), ('\u{1ed7}', '\u{1ed7}'), ('\u{1ed9}', '\u{1ed9}'), ('\u{1edb}', - '\u{1edb}'), ('\u{1edd}', '\u{1edd}'), ('\u{1edf}', '\u{1edf}'), ('\u{1ee1}', '\u{1ee1}'), - ('\u{1ee3}', '\u{1ee3}'), ('\u{1ee5}', '\u{1ee5}'), ('\u{1ee7}', '\u{1ee7}'), ('\u{1ee9}', - '\u{1ee9}'), ('\u{1eeb}', '\u{1eeb}'), ('\u{1eed}', '\u{1eed}'), ('\u{1eef}', '\u{1eef}'), - ('\u{1ef1}', '\u{1ef1}'), ('\u{1ef3}', '\u{1ef3}'), ('\u{1ef5}', '\u{1ef5}'), ('\u{1ef7}', - '\u{1ef7}'), ('\u{1ef9}', '\u{1ef9}'), ('\u{1efb}', '\u{1efb}'), ('\u{1efd}', '\u{1efd}'), - ('\u{1eff}', '\u{1f07}'), ('\u{1f10}', '\u{1f15}'), ('\u{1f20}', '\u{1f27}'), ('\u{1f30}', - '\u{1f37}'), ('\u{1f40}', '\u{1f45}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f60}', '\u{1f67}'), - ('\u{1f70}', '\u{1f7d}'), ('\u{1f80}', '\u{1f87}'), ('\u{1f90}', '\u{1f97}'), ('\u{1fa0}', - '\u{1fa7}'), ('\u{1fb0}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fb7}'), ('\u{1fbe}', '\u{1fbe}'), - ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fc7}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', - '\u{1fd7}'), ('\u{1fe0}', '\u{1fe7}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ff7}'), - ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{210a}', - '\u{210a}'), ('\u{210e}', '\u{210f}'), ('\u{2113}', '\u{2113}'), ('\u{212f}', '\u{212f}'), - ('\u{2134}', '\u{2134}'), ('\u{2139}', '\u{2139}'), ('\u{213c}', '\u{213d}'), ('\u{2146}', - '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2170}', '\u{217f}'), ('\u{2184}', '\u{2184}'), - ('\u{24d0}', '\u{24e9}'), ('\u{2c30}', '\u{2c5e}'), ('\u{2c61}', '\u{2c61}'), ('\u{2c65}', - '\u{2c66}'), ('\u{2c68}', '\u{2c68}'), ('\u{2c6a}', '\u{2c6a}'), ('\u{2c6c}', '\u{2c6c}'), - ('\u{2c71}', '\u{2c71}'), ('\u{2c73}', '\u{2c74}'), ('\u{2c76}', '\u{2c7d}'), ('\u{2c81}', - '\u{2c81}'), ('\u{2c83}', '\u{2c83}'), ('\u{2c85}', '\u{2c85}'), ('\u{2c87}', '\u{2c87}'), - ('\u{2c89}', '\u{2c89}'), ('\u{2c8b}', '\u{2c8b}'), ('\u{2c8d}', '\u{2c8d}'), ('\u{2c8f}', - '\u{2c8f}'), ('\u{2c91}', '\u{2c91}'), ('\u{2c93}', '\u{2c93}'), ('\u{2c95}', '\u{2c95}'), - ('\u{2c97}', '\u{2c97}'), ('\u{2c99}', '\u{2c99}'), ('\u{2c9b}', '\u{2c9b}'), ('\u{2c9d}', - '\u{2c9d}'), ('\u{2c9f}', '\u{2c9f}'), ('\u{2ca1}', '\u{2ca1}'), ('\u{2ca3}', '\u{2ca3}'), - ('\u{2ca5}', '\u{2ca5}'), ('\u{2ca7}', '\u{2ca7}'), ('\u{2ca9}', '\u{2ca9}'), ('\u{2cab}', - '\u{2cab}'), ('\u{2cad}', '\u{2cad}'), ('\u{2caf}', '\u{2caf}'), ('\u{2cb1}', '\u{2cb1}'), - ('\u{2cb3}', '\u{2cb3}'), ('\u{2cb5}', '\u{2cb5}'), ('\u{2cb7}', '\u{2cb7}'), ('\u{2cb9}', - '\u{2cb9}'), ('\u{2cbb}', '\u{2cbb}'), ('\u{2cbd}', '\u{2cbd}'), ('\u{2cbf}', '\u{2cbf}'), - ('\u{2cc1}', '\u{2cc1}'), ('\u{2cc3}', '\u{2cc3}'), ('\u{2cc5}', '\u{2cc5}'), ('\u{2cc7}', - '\u{2cc7}'), ('\u{2cc9}', '\u{2cc9}'), ('\u{2ccb}', '\u{2ccb}'), ('\u{2ccd}', '\u{2ccd}'), - ('\u{2ccf}', '\u{2ccf}'), ('\u{2cd1}', '\u{2cd1}'), ('\u{2cd3}', '\u{2cd3}'), ('\u{2cd5}', - '\u{2cd5}'), ('\u{2cd7}', '\u{2cd7}'), ('\u{2cd9}', '\u{2cd9}'), ('\u{2cdb}', '\u{2cdb}'), - ('\u{2cdd}', '\u{2cdd}'), ('\u{2cdf}', '\u{2cdf}'), ('\u{2ce1}', '\u{2ce1}'), ('\u{2ce3}', - '\u{2ce4}'), ('\u{2cec}', '\u{2cec}'), ('\u{2cee}', '\u{2cee}'), ('\u{2cf3}', '\u{2cf3}'), - ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{a641}', - '\u{a641}'), ('\u{a643}', '\u{a643}'), ('\u{a645}', '\u{a645}'), ('\u{a647}', '\u{a647}'), - ('\u{a649}', '\u{a649}'), ('\u{a64b}', '\u{a64b}'), ('\u{a64d}', '\u{a64d}'), ('\u{a64f}', - '\u{a64f}'), ('\u{a651}', '\u{a651}'), ('\u{a653}', '\u{a653}'), ('\u{a655}', '\u{a655}'), - ('\u{a657}', '\u{a657}'), ('\u{a659}', '\u{a659}'), ('\u{a65b}', '\u{a65b}'), ('\u{a65d}', - '\u{a65d}'), ('\u{a65f}', '\u{a65f}'), ('\u{a661}', '\u{a661}'), ('\u{a663}', '\u{a663}'), - ('\u{a665}', '\u{a665}'), ('\u{a667}', '\u{a667}'), ('\u{a669}', '\u{a669}'), ('\u{a66b}', - '\u{a66b}'), ('\u{a66d}', '\u{a66d}'), ('\u{a681}', '\u{a681}'), ('\u{a683}', '\u{a683}'), - ('\u{a685}', '\u{a685}'), ('\u{a687}', '\u{a687}'), ('\u{a689}', '\u{a689}'), ('\u{a68b}', - '\u{a68b}'), ('\u{a68d}', '\u{a68d}'), ('\u{a68f}', '\u{a68f}'), ('\u{a691}', '\u{a691}'), - ('\u{a693}', '\u{a693}'), ('\u{a695}', '\u{a695}'), ('\u{a697}', '\u{a697}'), ('\u{a699}', - '\u{a699}'), ('\u{a69b}', '\u{a69d}'), ('\u{a723}', '\u{a723}'), ('\u{a725}', '\u{a725}'), - ('\u{a727}', '\u{a727}'), ('\u{a729}', '\u{a729}'), ('\u{a72b}', '\u{a72b}'), ('\u{a72d}', - '\u{a72d}'), ('\u{a72f}', '\u{a731}'), ('\u{a733}', '\u{a733}'), ('\u{a735}', '\u{a735}'), - ('\u{a737}', '\u{a737}'), ('\u{a739}', '\u{a739}'), ('\u{a73b}', '\u{a73b}'), ('\u{a73d}', - '\u{a73d}'), ('\u{a73f}', '\u{a73f}'), ('\u{a741}', '\u{a741}'), ('\u{a743}', '\u{a743}'), - ('\u{a745}', '\u{a745}'), ('\u{a747}', '\u{a747}'), ('\u{a749}', '\u{a749}'), ('\u{a74b}', - '\u{a74b}'), ('\u{a74d}', '\u{a74d}'), ('\u{a74f}', '\u{a74f}'), ('\u{a751}', '\u{a751}'), - ('\u{a753}', '\u{a753}'), ('\u{a755}', '\u{a755}'), ('\u{a757}', '\u{a757}'), ('\u{a759}', - '\u{a759}'), ('\u{a75b}', '\u{a75b}'), ('\u{a75d}', '\u{a75d}'), ('\u{a75f}', '\u{a75f}'), - ('\u{a761}', '\u{a761}'), ('\u{a763}', '\u{a763}'), ('\u{a765}', '\u{a765}'), ('\u{a767}', - '\u{a767}'), ('\u{a769}', '\u{a769}'), ('\u{a76b}', '\u{a76b}'), ('\u{a76d}', '\u{a76d}'), - ('\u{a76f}', '\u{a778}'), ('\u{a77a}', '\u{a77a}'), ('\u{a77c}', '\u{a77c}'), ('\u{a77f}', - '\u{a77f}'), ('\u{a781}', '\u{a781}'), ('\u{a783}', '\u{a783}'), ('\u{a785}', '\u{a785}'), - ('\u{a787}', '\u{a787}'), ('\u{a78c}', '\u{a78c}'), ('\u{a78e}', '\u{a78e}'), ('\u{a791}', - '\u{a791}'), ('\u{a793}', '\u{a795}'), ('\u{a797}', '\u{a797}'), ('\u{a799}', '\u{a799}'), - ('\u{a79b}', '\u{a79b}'), ('\u{a79d}', '\u{a79d}'), ('\u{a79f}', '\u{a79f}'), ('\u{a7a1}', - '\u{a7a1}'), ('\u{a7a3}', '\u{a7a3}'), ('\u{a7a5}', '\u{a7a5}'), ('\u{a7a7}', '\u{a7a7}'), - ('\u{a7a9}', '\u{a7a9}'), ('\u{a7b5}', '\u{a7b5}'), ('\u{a7b7}', '\u{a7b7}'), ('\u{a7f8}', - '\u{a7fa}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab65}'), ('\u{ab70}', '\u{abbf}'), - ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{ff41}', '\u{ff5a}'), ('\u{10428}', - '\u{1044f}'), ('\u{10cc0}', '\u{10cf2}'), ('\u{118c0}', '\u{118df}'), ('\u{1d41a}', - '\u{1d433}'), ('\u{1d44e}', '\u{1d454}'), ('\u{1d456}', '\u{1d467}'), ('\u{1d482}', - '\u{1d49b}'), ('\u{1d4b6}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', - '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d4cf}'), ('\u{1d4ea}', '\u{1d503}'), ('\u{1d51e}', - '\u{1d537}'), ('\u{1d552}', '\u{1d56b}'), ('\u{1d586}', '\u{1d59f}'), ('\u{1d5ba}', - '\u{1d5d3}'), ('\u{1d5ee}', '\u{1d607}'), ('\u{1d622}', '\u{1d63b}'), ('\u{1d656}', - '\u{1d66f}'), ('\u{1d68a}', '\u{1d6a5}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', - '\u{1d6e1}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d71b}'), ('\u{1d736}', - '\u{1d74e}'), ('\u{1d750}', '\u{1d755}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', - '\u{1d78f}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7c9}'), ('\u{1d7cb}', - '\u{1d7cb}') - ]; + pub const Lowercase_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000, + 0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240, + 0x93faaaaaaaaaaaaa, 0xffffffffffffaa85, 0x01ffffffffefffff, 0x0000001f00000003, + 0x0000000000000000, 0x3c8a000000000020, 0xfffff00000010000, 0x192faaaaaae37fff, + 0xffff000000000000, 0xaaaaaaaaffffffff, 0xaaaaaaaaaaaaa802, 0xaaaaaaaaaaaad554, + 0x0000aaaaaaaaaaaa, 0xfffffffe00000000, 0x00000000000000ff, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 3, 3, 4, + 3, 5, 6, 7, 8, 0, 9, 10, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 3, + 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 21, 22, 23, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 25, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 27, 0, 0 + ], + r3: &[ + 0x0000000000000000, 0x3f00000000000000, 0xffffffffffffffff, 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaabfeaaaaa, 0x00ff00ff003f00ff, 0x3fff00ff00ff003f, 0x40df00ff00ff00ff, + 0x00dc00ff00cf00dc, 0x8002000000000000, 0x000000001fff0000, 0x321080000008c400, + 0xffff0000000043c0, 0x0000000000000010, 0x000003ffffff0000, 0xffff000000000000, + 0x3fda15627fffffff, 0x0008501aaaaaaaaa, 0x000020bfffffffff, 0x00002aaaaaaaaaaa, + 0x000000003aaaaaaa, 0xaaabaaa800000000, 0x95ffaaaaaaaaaaaa, 0x00a002aaaaba50aa, + 0x0700000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, 0x0000000007fffffe + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0xffffff0000000000, 0x000000000000ffff, 0x0007ffffffffffff, + 0x00000000ffffffff, 0x000ffffffc000000, 0x000000ffffdfc000, 0xebc000000ffffffc, + 0xfffffc000000ffef, 0x00ffffffc000000f, 0x00000ffffffc0000, 0xfc000000ffffffc0, + 0xffffc000000fffff, 0x0ffffffc000000ff, 0x0000ffffffc00000, 0x0000003ffffffc00, + 0xf0000003f7fffffc, 0xffc000000fdfffff, 0xffff0000003f7fff, 0xfffffc000000fdff, + 0x0000000000000bf7 + ], + }; pub fn Lowercase(c: char) -> bool { - super::bsearch_range_table(c, Lowercase_table) + super::trie_lookup_range_table(c, Lowercase_table) } - pub const Uppercase_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{de}'), ('\u{100}', '\u{100}'), - ('\u{102}', '\u{102}'), ('\u{104}', '\u{104}'), ('\u{106}', '\u{106}'), ('\u{108}', - '\u{108}'), ('\u{10a}', '\u{10a}'), ('\u{10c}', '\u{10c}'), ('\u{10e}', '\u{10e}'), - ('\u{110}', '\u{110}'), ('\u{112}', '\u{112}'), ('\u{114}', '\u{114}'), ('\u{116}', - '\u{116}'), ('\u{118}', '\u{118}'), ('\u{11a}', '\u{11a}'), ('\u{11c}', '\u{11c}'), - ('\u{11e}', '\u{11e}'), ('\u{120}', '\u{120}'), ('\u{122}', '\u{122}'), ('\u{124}', - '\u{124}'), ('\u{126}', '\u{126}'), ('\u{128}', '\u{128}'), ('\u{12a}', '\u{12a}'), - ('\u{12c}', '\u{12c}'), ('\u{12e}', '\u{12e}'), ('\u{130}', '\u{130}'), ('\u{132}', - '\u{132}'), ('\u{134}', '\u{134}'), ('\u{136}', '\u{136}'), ('\u{139}', '\u{139}'), - ('\u{13b}', '\u{13b}'), ('\u{13d}', '\u{13d}'), ('\u{13f}', '\u{13f}'), ('\u{141}', - '\u{141}'), ('\u{143}', '\u{143}'), ('\u{145}', '\u{145}'), ('\u{147}', '\u{147}'), - ('\u{14a}', '\u{14a}'), ('\u{14c}', '\u{14c}'), ('\u{14e}', '\u{14e}'), ('\u{150}', - '\u{150}'), ('\u{152}', '\u{152}'), ('\u{154}', '\u{154}'), ('\u{156}', '\u{156}'), - ('\u{158}', '\u{158}'), ('\u{15a}', '\u{15a}'), ('\u{15c}', '\u{15c}'), ('\u{15e}', - '\u{15e}'), ('\u{160}', '\u{160}'), ('\u{162}', '\u{162}'), ('\u{164}', '\u{164}'), - ('\u{166}', '\u{166}'), ('\u{168}', '\u{168}'), ('\u{16a}', '\u{16a}'), ('\u{16c}', - '\u{16c}'), ('\u{16e}', '\u{16e}'), ('\u{170}', '\u{170}'), ('\u{172}', '\u{172}'), - ('\u{174}', '\u{174}'), ('\u{176}', '\u{176}'), ('\u{178}', '\u{179}'), ('\u{17b}', - '\u{17b}'), ('\u{17d}', '\u{17d}'), ('\u{181}', '\u{182}'), ('\u{184}', '\u{184}'), - ('\u{186}', '\u{187}'), ('\u{189}', '\u{18b}'), ('\u{18e}', '\u{191}'), ('\u{193}', - '\u{194}'), ('\u{196}', '\u{198}'), ('\u{19c}', '\u{19d}'), ('\u{19f}', '\u{1a0}'), - ('\u{1a2}', '\u{1a2}'), ('\u{1a4}', '\u{1a4}'), ('\u{1a6}', '\u{1a7}'), ('\u{1a9}', - '\u{1a9}'), ('\u{1ac}', '\u{1ac}'), ('\u{1ae}', '\u{1af}'), ('\u{1b1}', '\u{1b3}'), - ('\u{1b5}', '\u{1b5}'), ('\u{1b7}', '\u{1b8}'), ('\u{1bc}', '\u{1bc}'), ('\u{1c4}', - '\u{1c4}'), ('\u{1c7}', '\u{1c7}'), ('\u{1ca}', '\u{1ca}'), ('\u{1cd}', '\u{1cd}'), - ('\u{1cf}', '\u{1cf}'), ('\u{1d1}', '\u{1d1}'), ('\u{1d3}', '\u{1d3}'), ('\u{1d5}', - '\u{1d5}'), ('\u{1d7}', '\u{1d7}'), ('\u{1d9}', '\u{1d9}'), ('\u{1db}', '\u{1db}'), - ('\u{1de}', '\u{1de}'), ('\u{1e0}', '\u{1e0}'), ('\u{1e2}', '\u{1e2}'), ('\u{1e4}', - '\u{1e4}'), ('\u{1e6}', '\u{1e6}'), ('\u{1e8}', '\u{1e8}'), ('\u{1ea}', '\u{1ea}'), - ('\u{1ec}', '\u{1ec}'), ('\u{1ee}', '\u{1ee}'), ('\u{1f1}', '\u{1f1}'), ('\u{1f4}', - '\u{1f4}'), ('\u{1f6}', '\u{1f8}'), ('\u{1fa}', '\u{1fa}'), ('\u{1fc}', '\u{1fc}'), - ('\u{1fe}', '\u{1fe}'), ('\u{200}', '\u{200}'), ('\u{202}', '\u{202}'), ('\u{204}', - '\u{204}'), ('\u{206}', '\u{206}'), ('\u{208}', '\u{208}'), ('\u{20a}', '\u{20a}'), - ('\u{20c}', '\u{20c}'), ('\u{20e}', '\u{20e}'), ('\u{210}', '\u{210}'), ('\u{212}', - '\u{212}'), ('\u{214}', '\u{214}'), ('\u{216}', '\u{216}'), ('\u{218}', '\u{218}'), - ('\u{21a}', '\u{21a}'), ('\u{21c}', '\u{21c}'), ('\u{21e}', '\u{21e}'), ('\u{220}', - '\u{220}'), ('\u{222}', '\u{222}'), ('\u{224}', '\u{224}'), ('\u{226}', '\u{226}'), - ('\u{228}', '\u{228}'), ('\u{22a}', '\u{22a}'), ('\u{22c}', '\u{22c}'), ('\u{22e}', - '\u{22e}'), ('\u{230}', '\u{230}'), ('\u{232}', '\u{232}'), ('\u{23a}', '\u{23b}'), - ('\u{23d}', '\u{23e}'), ('\u{241}', '\u{241}'), ('\u{243}', '\u{246}'), ('\u{248}', - '\u{248}'), ('\u{24a}', '\u{24a}'), ('\u{24c}', '\u{24c}'), ('\u{24e}', '\u{24e}'), - ('\u{370}', '\u{370}'), ('\u{372}', '\u{372}'), ('\u{376}', '\u{376}'), ('\u{37f}', - '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', '\u{38c}'), - ('\u{38e}', '\u{38f}'), ('\u{391}', '\u{3a1}'), ('\u{3a3}', '\u{3ab}'), ('\u{3cf}', - '\u{3cf}'), ('\u{3d2}', '\u{3d4}'), ('\u{3d8}', '\u{3d8}'), ('\u{3da}', '\u{3da}'), - ('\u{3dc}', '\u{3dc}'), ('\u{3de}', '\u{3de}'), ('\u{3e0}', '\u{3e0}'), ('\u{3e2}', - '\u{3e2}'), ('\u{3e4}', '\u{3e4}'), ('\u{3e6}', '\u{3e6}'), ('\u{3e8}', '\u{3e8}'), - ('\u{3ea}', '\u{3ea}'), ('\u{3ec}', '\u{3ec}'), ('\u{3ee}', '\u{3ee}'), ('\u{3f4}', - '\u{3f4}'), ('\u{3f7}', '\u{3f7}'), ('\u{3f9}', '\u{3fa}'), ('\u{3fd}', '\u{42f}'), - ('\u{460}', '\u{460}'), ('\u{462}', '\u{462}'), ('\u{464}', '\u{464}'), ('\u{466}', - '\u{466}'), ('\u{468}', '\u{468}'), ('\u{46a}', '\u{46a}'), ('\u{46c}', '\u{46c}'), - ('\u{46e}', '\u{46e}'), ('\u{470}', '\u{470}'), ('\u{472}', '\u{472}'), ('\u{474}', - '\u{474}'), ('\u{476}', '\u{476}'), ('\u{478}', '\u{478}'), ('\u{47a}', '\u{47a}'), - ('\u{47c}', '\u{47c}'), ('\u{47e}', '\u{47e}'), ('\u{480}', '\u{480}'), ('\u{48a}', - '\u{48a}'), ('\u{48c}', '\u{48c}'), ('\u{48e}', '\u{48e}'), ('\u{490}', '\u{490}'), - ('\u{492}', '\u{492}'), ('\u{494}', '\u{494}'), ('\u{496}', '\u{496}'), ('\u{498}', - '\u{498}'), ('\u{49a}', '\u{49a}'), ('\u{49c}', '\u{49c}'), ('\u{49e}', '\u{49e}'), - ('\u{4a0}', '\u{4a0}'), ('\u{4a2}', '\u{4a2}'), ('\u{4a4}', '\u{4a4}'), ('\u{4a6}', - '\u{4a6}'), ('\u{4a8}', '\u{4a8}'), ('\u{4aa}', '\u{4aa}'), ('\u{4ac}', '\u{4ac}'), - ('\u{4ae}', '\u{4ae}'), ('\u{4b0}', '\u{4b0}'), ('\u{4b2}', '\u{4b2}'), ('\u{4b4}', - '\u{4b4}'), ('\u{4b6}', '\u{4b6}'), ('\u{4b8}', '\u{4b8}'), ('\u{4ba}', '\u{4ba}'), - ('\u{4bc}', '\u{4bc}'), ('\u{4be}', '\u{4be}'), ('\u{4c0}', '\u{4c1}'), ('\u{4c3}', - '\u{4c3}'), ('\u{4c5}', '\u{4c5}'), ('\u{4c7}', '\u{4c7}'), ('\u{4c9}', '\u{4c9}'), - ('\u{4cb}', '\u{4cb}'), ('\u{4cd}', '\u{4cd}'), ('\u{4d0}', '\u{4d0}'), ('\u{4d2}', - '\u{4d2}'), ('\u{4d4}', '\u{4d4}'), ('\u{4d6}', '\u{4d6}'), ('\u{4d8}', '\u{4d8}'), - ('\u{4da}', '\u{4da}'), ('\u{4dc}', '\u{4dc}'), ('\u{4de}', '\u{4de}'), ('\u{4e0}', - '\u{4e0}'), ('\u{4e2}', '\u{4e2}'), ('\u{4e4}', '\u{4e4}'), ('\u{4e6}', '\u{4e6}'), - ('\u{4e8}', '\u{4e8}'), ('\u{4ea}', '\u{4ea}'), ('\u{4ec}', '\u{4ec}'), ('\u{4ee}', - '\u{4ee}'), ('\u{4f0}', '\u{4f0}'), ('\u{4f2}', '\u{4f2}'), ('\u{4f4}', '\u{4f4}'), - ('\u{4f6}', '\u{4f6}'), ('\u{4f8}', '\u{4f8}'), ('\u{4fa}', '\u{4fa}'), ('\u{4fc}', - '\u{4fc}'), ('\u{4fe}', '\u{4fe}'), ('\u{500}', '\u{500}'), ('\u{502}', '\u{502}'), - ('\u{504}', '\u{504}'), ('\u{506}', '\u{506}'), ('\u{508}', '\u{508}'), ('\u{50a}', - '\u{50a}'), ('\u{50c}', '\u{50c}'), ('\u{50e}', '\u{50e}'), ('\u{510}', '\u{510}'), - ('\u{512}', '\u{512}'), ('\u{514}', '\u{514}'), ('\u{516}', '\u{516}'), ('\u{518}', - '\u{518}'), ('\u{51a}', '\u{51a}'), ('\u{51c}', '\u{51c}'), ('\u{51e}', '\u{51e}'), - ('\u{520}', '\u{520}'), ('\u{522}', '\u{522}'), ('\u{524}', '\u{524}'), ('\u{526}', - '\u{526}'), ('\u{528}', '\u{528}'), ('\u{52a}', '\u{52a}'), ('\u{52c}', '\u{52c}'), - ('\u{52e}', '\u{52e}'), ('\u{531}', '\u{556}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', - '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{13a0}', '\u{13f5}'), ('\u{1e00}', '\u{1e00}'), - ('\u{1e02}', '\u{1e02}'), ('\u{1e04}', '\u{1e04}'), ('\u{1e06}', '\u{1e06}'), ('\u{1e08}', - '\u{1e08}'), ('\u{1e0a}', '\u{1e0a}'), ('\u{1e0c}', '\u{1e0c}'), ('\u{1e0e}', '\u{1e0e}'), - ('\u{1e10}', '\u{1e10}'), ('\u{1e12}', '\u{1e12}'), ('\u{1e14}', '\u{1e14}'), ('\u{1e16}', - '\u{1e16}'), ('\u{1e18}', '\u{1e18}'), ('\u{1e1a}', '\u{1e1a}'), ('\u{1e1c}', '\u{1e1c}'), - ('\u{1e1e}', '\u{1e1e}'), ('\u{1e20}', '\u{1e20}'), ('\u{1e22}', '\u{1e22}'), ('\u{1e24}', - '\u{1e24}'), ('\u{1e26}', '\u{1e26}'), ('\u{1e28}', '\u{1e28}'), ('\u{1e2a}', '\u{1e2a}'), - ('\u{1e2c}', '\u{1e2c}'), ('\u{1e2e}', '\u{1e2e}'), ('\u{1e30}', '\u{1e30}'), ('\u{1e32}', - '\u{1e32}'), ('\u{1e34}', '\u{1e34}'), ('\u{1e36}', '\u{1e36}'), ('\u{1e38}', '\u{1e38}'), - ('\u{1e3a}', '\u{1e3a}'), ('\u{1e3c}', '\u{1e3c}'), ('\u{1e3e}', '\u{1e3e}'), ('\u{1e40}', - '\u{1e40}'), ('\u{1e42}', '\u{1e42}'), ('\u{1e44}', '\u{1e44}'), ('\u{1e46}', '\u{1e46}'), - ('\u{1e48}', '\u{1e48}'), ('\u{1e4a}', '\u{1e4a}'), ('\u{1e4c}', '\u{1e4c}'), ('\u{1e4e}', - '\u{1e4e}'), ('\u{1e50}', '\u{1e50}'), ('\u{1e52}', '\u{1e52}'), ('\u{1e54}', '\u{1e54}'), - ('\u{1e56}', '\u{1e56}'), ('\u{1e58}', '\u{1e58}'), ('\u{1e5a}', '\u{1e5a}'), ('\u{1e5c}', - '\u{1e5c}'), ('\u{1e5e}', '\u{1e5e}'), ('\u{1e60}', '\u{1e60}'), ('\u{1e62}', '\u{1e62}'), - ('\u{1e64}', '\u{1e64}'), ('\u{1e66}', '\u{1e66}'), ('\u{1e68}', '\u{1e68}'), ('\u{1e6a}', - '\u{1e6a}'), ('\u{1e6c}', '\u{1e6c}'), ('\u{1e6e}', '\u{1e6e}'), ('\u{1e70}', '\u{1e70}'), - ('\u{1e72}', '\u{1e72}'), ('\u{1e74}', '\u{1e74}'), ('\u{1e76}', '\u{1e76}'), ('\u{1e78}', - '\u{1e78}'), ('\u{1e7a}', '\u{1e7a}'), ('\u{1e7c}', '\u{1e7c}'), ('\u{1e7e}', '\u{1e7e}'), - ('\u{1e80}', '\u{1e80}'), ('\u{1e82}', '\u{1e82}'), ('\u{1e84}', '\u{1e84}'), ('\u{1e86}', - '\u{1e86}'), ('\u{1e88}', '\u{1e88}'), ('\u{1e8a}', '\u{1e8a}'), ('\u{1e8c}', '\u{1e8c}'), - ('\u{1e8e}', '\u{1e8e}'), ('\u{1e90}', '\u{1e90}'), ('\u{1e92}', '\u{1e92}'), ('\u{1e94}', - '\u{1e94}'), ('\u{1e9e}', '\u{1e9e}'), ('\u{1ea0}', '\u{1ea0}'), ('\u{1ea2}', '\u{1ea2}'), - ('\u{1ea4}', '\u{1ea4}'), ('\u{1ea6}', '\u{1ea6}'), ('\u{1ea8}', '\u{1ea8}'), ('\u{1eaa}', - '\u{1eaa}'), ('\u{1eac}', '\u{1eac}'), ('\u{1eae}', '\u{1eae}'), ('\u{1eb0}', '\u{1eb0}'), - ('\u{1eb2}', '\u{1eb2}'), ('\u{1eb4}', '\u{1eb4}'), ('\u{1eb6}', '\u{1eb6}'), ('\u{1eb8}', - '\u{1eb8}'), ('\u{1eba}', '\u{1eba}'), ('\u{1ebc}', '\u{1ebc}'), ('\u{1ebe}', '\u{1ebe}'), - ('\u{1ec0}', '\u{1ec0}'), ('\u{1ec2}', '\u{1ec2}'), ('\u{1ec4}', '\u{1ec4}'), ('\u{1ec6}', - '\u{1ec6}'), ('\u{1ec8}', '\u{1ec8}'), ('\u{1eca}', '\u{1eca}'), ('\u{1ecc}', '\u{1ecc}'), - ('\u{1ece}', '\u{1ece}'), ('\u{1ed0}', '\u{1ed0}'), ('\u{1ed2}', '\u{1ed2}'), ('\u{1ed4}', - '\u{1ed4}'), ('\u{1ed6}', '\u{1ed6}'), ('\u{1ed8}', '\u{1ed8}'), ('\u{1eda}', '\u{1eda}'), - ('\u{1edc}', '\u{1edc}'), ('\u{1ede}', '\u{1ede}'), ('\u{1ee0}', '\u{1ee0}'), ('\u{1ee2}', - '\u{1ee2}'), ('\u{1ee4}', '\u{1ee4}'), ('\u{1ee6}', '\u{1ee6}'), ('\u{1ee8}', '\u{1ee8}'), - ('\u{1eea}', '\u{1eea}'), ('\u{1eec}', '\u{1eec}'), ('\u{1eee}', '\u{1eee}'), ('\u{1ef0}', - '\u{1ef0}'), ('\u{1ef2}', '\u{1ef2}'), ('\u{1ef4}', '\u{1ef4}'), ('\u{1ef6}', '\u{1ef6}'), - ('\u{1ef8}', '\u{1ef8}'), ('\u{1efa}', '\u{1efa}'), ('\u{1efc}', '\u{1efc}'), ('\u{1efe}', - '\u{1efe}'), ('\u{1f08}', '\u{1f0f}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f28}', '\u{1f2f}'), - ('\u{1f38}', '\u{1f3f}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', - '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f5f}'), ('\u{1f68}', '\u{1f6f}'), - ('\u{1fb8}', '\u{1fbb}'), ('\u{1fc8}', '\u{1fcb}'), ('\u{1fd8}', '\u{1fdb}'), ('\u{1fe8}', - '\u{1fec}'), ('\u{1ff8}', '\u{1ffb}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), - ('\u{210b}', '\u{210d}'), ('\u{2110}', '\u{2112}'), ('\u{2115}', '\u{2115}'), ('\u{2119}', - '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}', '\u{2128}'), - ('\u{212a}', '\u{212d}'), ('\u{2130}', '\u{2133}'), ('\u{213e}', '\u{213f}'), ('\u{2145}', - '\u{2145}'), ('\u{2160}', '\u{216f}'), ('\u{2183}', '\u{2183}'), ('\u{24b6}', '\u{24cf}'), - ('\u{2c00}', '\u{2c2e}'), ('\u{2c60}', '\u{2c60}'), ('\u{2c62}', '\u{2c64}'), ('\u{2c67}', - '\u{2c67}'), ('\u{2c69}', '\u{2c69}'), ('\u{2c6b}', '\u{2c6b}'), ('\u{2c6d}', '\u{2c70}'), - ('\u{2c72}', '\u{2c72}'), ('\u{2c75}', '\u{2c75}'), ('\u{2c7e}', '\u{2c80}'), ('\u{2c82}', - '\u{2c82}'), ('\u{2c84}', '\u{2c84}'), ('\u{2c86}', '\u{2c86}'), ('\u{2c88}', '\u{2c88}'), - ('\u{2c8a}', '\u{2c8a}'), ('\u{2c8c}', '\u{2c8c}'), ('\u{2c8e}', '\u{2c8e}'), ('\u{2c90}', - '\u{2c90}'), ('\u{2c92}', '\u{2c92}'), ('\u{2c94}', '\u{2c94}'), ('\u{2c96}', '\u{2c96}'), - ('\u{2c98}', '\u{2c98}'), ('\u{2c9a}', '\u{2c9a}'), ('\u{2c9c}', '\u{2c9c}'), ('\u{2c9e}', - '\u{2c9e}'), ('\u{2ca0}', '\u{2ca0}'), ('\u{2ca2}', '\u{2ca2}'), ('\u{2ca4}', '\u{2ca4}'), - ('\u{2ca6}', '\u{2ca6}'), ('\u{2ca8}', '\u{2ca8}'), ('\u{2caa}', '\u{2caa}'), ('\u{2cac}', - '\u{2cac}'), ('\u{2cae}', '\u{2cae}'), ('\u{2cb0}', '\u{2cb0}'), ('\u{2cb2}', '\u{2cb2}'), - ('\u{2cb4}', '\u{2cb4}'), ('\u{2cb6}', '\u{2cb6}'), ('\u{2cb8}', '\u{2cb8}'), ('\u{2cba}', - '\u{2cba}'), ('\u{2cbc}', '\u{2cbc}'), ('\u{2cbe}', '\u{2cbe}'), ('\u{2cc0}', '\u{2cc0}'), - ('\u{2cc2}', '\u{2cc2}'), ('\u{2cc4}', '\u{2cc4}'), ('\u{2cc6}', '\u{2cc6}'), ('\u{2cc8}', - '\u{2cc8}'), ('\u{2cca}', '\u{2cca}'), ('\u{2ccc}', '\u{2ccc}'), ('\u{2cce}', '\u{2cce}'), - ('\u{2cd0}', '\u{2cd0}'), ('\u{2cd2}', '\u{2cd2}'), ('\u{2cd4}', '\u{2cd4}'), ('\u{2cd6}', - '\u{2cd6}'), ('\u{2cd8}', '\u{2cd8}'), ('\u{2cda}', '\u{2cda}'), ('\u{2cdc}', '\u{2cdc}'), - ('\u{2cde}', '\u{2cde}'), ('\u{2ce0}', '\u{2ce0}'), ('\u{2ce2}', '\u{2ce2}'), ('\u{2ceb}', - '\u{2ceb}'), ('\u{2ced}', '\u{2ced}'), ('\u{2cf2}', '\u{2cf2}'), ('\u{a640}', '\u{a640}'), - ('\u{a642}', '\u{a642}'), ('\u{a644}', '\u{a644}'), ('\u{a646}', '\u{a646}'), ('\u{a648}', - '\u{a648}'), ('\u{a64a}', '\u{a64a}'), ('\u{a64c}', '\u{a64c}'), ('\u{a64e}', '\u{a64e}'), - ('\u{a650}', '\u{a650}'), ('\u{a652}', '\u{a652}'), ('\u{a654}', '\u{a654}'), ('\u{a656}', - '\u{a656}'), ('\u{a658}', '\u{a658}'), ('\u{a65a}', '\u{a65a}'), ('\u{a65c}', '\u{a65c}'), - ('\u{a65e}', '\u{a65e}'), ('\u{a660}', '\u{a660}'), ('\u{a662}', '\u{a662}'), ('\u{a664}', - '\u{a664}'), ('\u{a666}', '\u{a666}'), ('\u{a668}', '\u{a668}'), ('\u{a66a}', '\u{a66a}'), - ('\u{a66c}', '\u{a66c}'), ('\u{a680}', '\u{a680}'), ('\u{a682}', '\u{a682}'), ('\u{a684}', - '\u{a684}'), ('\u{a686}', '\u{a686}'), ('\u{a688}', '\u{a688}'), ('\u{a68a}', '\u{a68a}'), - ('\u{a68c}', '\u{a68c}'), ('\u{a68e}', '\u{a68e}'), ('\u{a690}', '\u{a690}'), ('\u{a692}', - '\u{a692}'), ('\u{a694}', '\u{a694}'), ('\u{a696}', '\u{a696}'), ('\u{a698}', '\u{a698}'), - ('\u{a69a}', '\u{a69a}'), ('\u{a722}', '\u{a722}'), ('\u{a724}', '\u{a724}'), ('\u{a726}', - '\u{a726}'), ('\u{a728}', '\u{a728}'), ('\u{a72a}', '\u{a72a}'), ('\u{a72c}', '\u{a72c}'), - ('\u{a72e}', '\u{a72e}'), ('\u{a732}', '\u{a732}'), ('\u{a734}', '\u{a734}'), ('\u{a736}', - '\u{a736}'), ('\u{a738}', '\u{a738}'), ('\u{a73a}', '\u{a73a}'), ('\u{a73c}', '\u{a73c}'), - ('\u{a73e}', '\u{a73e}'), ('\u{a740}', '\u{a740}'), ('\u{a742}', '\u{a742}'), ('\u{a744}', - '\u{a744}'), ('\u{a746}', '\u{a746}'), ('\u{a748}', '\u{a748}'), ('\u{a74a}', '\u{a74a}'), - ('\u{a74c}', '\u{a74c}'), ('\u{a74e}', '\u{a74e}'), ('\u{a750}', '\u{a750}'), ('\u{a752}', - '\u{a752}'), ('\u{a754}', '\u{a754}'), ('\u{a756}', '\u{a756}'), ('\u{a758}', '\u{a758}'), - ('\u{a75a}', '\u{a75a}'), ('\u{a75c}', '\u{a75c}'), ('\u{a75e}', '\u{a75e}'), ('\u{a760}', - '\u{a760}'), ('\u{a762}', '\u{a762}'), ('\u{a764}', '\u{a764}'), ('\u{a766}', '\u{a766}'), - ('\u{a768}', '\u{a768}'), ('\u{a76a}', '\u{a76a}'), ('\u{a76c}', '\u{a76c}'), ('\u{a76e}', - '\u{a76e}'), ('\u{a779}', '\u{a779}'), ('\u{a77b}', '\u{a77b}'), ('\u{a77d}', '\u{a77e}'), - ('\u{a780}', '\u{a780}'), ('\u{a782}', '\u{a782}'), ('\u{a784}', '\u{a784}'), ('\u{a786}', - '\u{a786}'), ('\u{a78b}', '\u{a78b}'), ('\u{a78d}', '\u{a78d}'), ('\u{a790}', '\u{a790}'), - ('\u{a792}', '\u{a792}'), ('\u{a796}', '\u{a796}'), ('\u{a798}', '\u{a798}'), ('\u{a79a}', - '\u{a79a}'), ('\u{a79c}', '\u{a79c}'), ('\u{a79e}', '\u{a79e}'), ('\u{a7a0}', '\u{a7a0}'), - ('\u{a7a2}', '\u{a7a2}'), ('\u{a7a4}', '\u{a7a4}'), ('\u{a7a6}', '\u{a7a6}'), ('\u{a7a8}', - '\u{a7a8}'), ('\u{a7aa}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b4}'), ('\u{a7b6}', '\u{a7b6}'), - ('\u{ff21}', '\u{ff3a}'), ('\u{10400}', '\u{10427}'), ('\u{10c80}', '\u{10cb2}'), - ('\u{118a0}', '\u{118bf}'), ('\u{1d400}', '\u{1d419}'), ('\u{1d434}', '\u{1d44d}'), - ('\u{1d468}', '\u{1d481}'), ('\u{1d49c}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), - ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), - ('\u{1d4ae}', '\u{1d4b5}'), ('\u{1d4d0}', '\u{1d4e9}'), ('\u{1d504}', '\u{1d505}'), - ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), - ('\u{1d538}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), - ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d56c}', '\u{1d585}'), - ('\u{1d5a0}', '\u{1d5b9}'), ('\u{1d5d4}', '\u{1d5ed}'), ('\u{1d608}', '\u{1d621}'), - ('\u{1d63c}', '\u{1d655}'), ('\u{1d670}', '\u{1d689}'), ('\u{1d6a8}', '\u{1d6c0}'), - ('\u{1d6e2}', '\u{1d6fa}'), ('\u{1d71c}', '\u{1d734}'), ('\u{1d756}', '\u{1d76e}'), - ('\u{1d790}', '\u{1d7a8}'), ('\u{1d7ca}', '\u{1d7ca}'), ('\u{1f130}', '\u{1f149}'), - ('\u{1f150}', '\u{1f169}'), ('\u{1f170}', '\u{1f189}') - ]; + pub const Uppercase_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff, + 0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490, + 0x6c05555555555555, 0x000000000000557a, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x8045000000000000, 0x00000ffbfffed740, 0xe6905555551c8000, + 0x0000ffffffffffff, 0x5555555500000000, 0x5555555555555401, 0x5555555555552aab, + 0xfffe555555555555, 0x00000000007fffff, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 5, + 4, 6, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 4, + 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 0, 20, 21, 22, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 23, 0, 0, 0 + ], + r3: &[ + 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x003fffffffffffff, + 0x5555555555555555, 0x5555555540155555, 0xff00ff003f00ff00, 0x0000ff00aa003f00, + 0x0f00000000000000, 0x0f001f000f000f00, 0xc00f3d503e273884, 0x0000ffff00000020, + 0x0000000000000008, 0xffc0000000000000, 0x000000000000ffff, 0x00007fffffffffff, + 0xc025ea9d00000000, 0x0004280555555555, 0x0000155555555555, 0x0000000005555555, + 0x5554555400000000, 0x6a00555555555555, 0x005f3d5555452855, 0x07fffffe00000000 + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x000000ffffffffff, 0x0007ffffffffffff, 0xffffffff00000000, + 0xfff0000003ffffff, 0xffffff0000003fff, 0x003fde64d0000003, 0x000003ffffff0000, + 0x7b0000001fdfe7b0, 0xfffff0000001fc5f, 0x03ffffff0000003f, 0x00003ffffff00000, + 0xf0000003ffffff00, 0xffff0000003fffff, 0xffffff00000003ff, 0x07fffffc00000001, + 0x001ffffff0000000, 0x00007fffffc00000, 0x000001ffffff0000, 0x0000000000000400, + 0xffff000000000000, 0xffff03ffffff03ff, 0x00000000000003ff + ], + }; pub fn Uppercase(c: char) -> bool { - super::bsearch_range_table(c, Uppercase_table) + super::trie_lookup_range_table(c, Uppercase_table) } - pub const XID_Continue_table: &'static [(char, char)] = &[ - ('\u{30}', '\u{39}'), ('\u{41}', '\u{5a}'), ('\u{5f}', '\u{5f}'), ('\u{61}', '\u{7a}'), - ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), ('\u{b7}', '\u{b7}'), ('\u{ba}', '\u{ba}'), - ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), ('\u{2c6}', '\u{2d1}'), - ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', '\u{2ee}'), ('\u{300}', - '\u{374}'), ('\u{376}', '\u{377}'), ('\u{37b}', '\u{37d}'), ('\u{37f}', '\u{37f}'), - ('\u{386}', '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', - '\u{3f5}'), ('\u{3f7}', '\u{481}'), ('\u{483}', '\u{487}'), ('\u{48a}', '\u{52f}'), - ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{561}', '\u{587}'), ('\u{591}', - '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), - ('\u{5c7}', '\u{5c7}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{610}', - '\u{61a}'), ('\u{620}', '\u{669}'), ('\u{66e}', '\u{6d3}'), ('\u{6d5}', '\u{6dc}'), - ('\u{6df}', '\u{6e8}'), ('\u{6ea}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), ('\u{710}', - '\u{74a}'), ('\u{74d}', '\u{7b1}'), ('\u{7c0}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), - ('\u{800}', '\u{82d}'), ('\u{840}', '\u{85b}'), ('\u{8a0}', '\u{8b4}'), ('\u{8e3}', - '\u{963}'), ('\u{966}', '\u{96f}'), ('\u{971}', '\u{983}'), ('\u{985}', '\u{98c}'), - ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', - '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bc}', '\u{9c4}'), ('\u{9c7}', '\u{9c8}'), - ('\u{9cb}', '\u{9ce}'), ('\u{9d7}', '\u{9d7}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', - '\u{9e3}'), ('\u{9e6}', '\u{9f1}'), ('\u{a01}', '\u{a03}'), ('\u{a05}', '\u{a0a}'), - ('\u{a0f}', '\u{a10}'), ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', - '\u{a33}'), ('\u{a35}', '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a3c}', '\u{a3c}'), - ('\u{a3e}', '\u{a42}'), ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', - '\u{a51}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a66}', '\u{a75}'), - ('\u{a81}', '\u{a83}'), ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', - '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), - ('\u{abc}', '\u{ac5}'), ('\u{ac7}', '\u{ac9}'), ('\u{acb}', '\u{acd}'), ('\u{ad0}', - '\u{ad0}'), ('\u{ae0}', '\u{ae3}'), ('\u{ae6}', '\u{aef}'), ('\u{af9}', '\u{af9}'), - ('\u{b01}', '\u{b03}'), ('\u{b05}', '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', - '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), - ('\u{b3c}', '\u{b44}'), ('\u{b47}', '\u{b48}'), ('\u{b4b}', '\u{b4d}'), ('\u{b56}', - '\u{b57}'), ('\u{b5c}', '\u{b5d}'), ('\u{b5f}', '\u{b63}'), ('\u{b66}', '\u{b6f}'), - ('\u{b71}', '\u{b71}'), ('\u{b82}', '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', - '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), - ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', - '\u{bb9}'), ('\u{bbe}', '\u{bc2}'), ('\u{bc6}', '\u{bc8}'), ('\u{bca}', '\u{bcd}'), - ('\u{bd0}', '\u{bd0}'), ('\u{bd7}', '\u{bd7}'), ('\u{be6}', '\u{bef}'), ('\u{c00}', - '\u{c03}'), ('\u{c05}', '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), - ('\u{c2a}', '\u{c39}'), ('\u{c3d}', '\u{c44}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', - '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('\u{c58}', '\u{c5a}'), ('\u{c60}', '\u{c63}'), - ('\u{c66}', '\u{c6f}'), ('\u{c81}', '\u{c83}'), ('\u{c85}', '\u{c8c}'), ('\u{c8e}', - '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), - ('\u{cbc}', '\u{cc4}'), ('\u{cc6}', '\u{cc8}'), ('\u{cca}', '\u{ccd}'), ('\u{cd5}', - '\u{cd6}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', '\u{ce3}'), ('\u{ce6}', '\u{cef}'), - ('\u{cf1}', '\u{cf2}'), ('\u{d01}', '\u{d03}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', - '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d44}'), ('\u{d46}', '\u{d48}'), - ('\u{d4a}', '\u{d4e}'), ('\u{d57}', '\u{d57}'), ('\u{d5f}', '\u{d63}'), ('\u{d66}', - '\u{d6f}'), ('\u{d7a}', '\u{d7f}'), ('\u{d82}', '\u{d83}'), ('\u{d85}', '\u{d96}'), - ('\u{d9a}', '\u{db1}'), ('\u{db3}', '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', - '\u{dc6}'), ('\u{dca}', '\u{dca}'), ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), - ('\u{dd8}', '\u{ddf}'), ('\u{de6}', '\u{def}'), ('\u{df2}', '\u{df3}'), ('\u{e01}', - '\u{e3a}'), ('\u{e40}', '\u{e4e}'), ('\u{e50}', '\u{e59}'), ('\u{e81}', '\u{e82}'), - ('\u{e84}', '\u{e84}'), ('\u{e87}', '\u{e88}'), ('\u{e8a}', '\u{e8a}'), ('\u{e8d}', - '\u{e8d}'), ('\u{e94}', '\u{e97}'), ('\u{e99}', '\u{e9f}'), ('\u{ea1}', '\u{ea3}'), - ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), ('\u{eaa}', '\u{eab}'), ('\u{ead}', - '\u{eb9}'), ('\u{ebb}', '\u{ebd}'), ('\u{ec0}', '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), - ('\u{ec8}', '\u{ecd}'), ('\u{ed0}', '\u{ed9}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', - '\u{f00}'), ('\u{f18}', '\u{f19}'), ('\u{f20}', '\u{f29}'), ('\u{f35}', '\u{f35}'), - ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), ('\u{f3e}', '\u{f47}'), ('\u{f49}', - '\u{f6c}'), ('\u{f71}', '\u{f84}'), ('\u{f86}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), - ('\u{fc6}', '\u{fc6}'), ('\u{1000}', '\u{1049}'), ('\u{1050}', '\u{109d}'), ('\u{10a0}', - '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), - ('\u{10fc}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', - '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), - ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', - '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), - ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{135d}', '\u{135f}'), ('\u{1369}', - '\u{1371}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f5}'), ('\u{13f8}', '\u{13fd}'), - ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', - '\u{16ea}'), ('\u{16ee}', '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1714}'), - ('\u{1720}', '\u{1734}'), ('\u{1740}', '\u{1753}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', - '\u{1770}'), ('\u{1772}', '\u{1773}'), ('\u{1780}', '\u{17d3}'), ('\u{17d7}', '\u{17d7}'), - ('\u{17dc}', '\u{17dd}'), ('\u{17e0}', '\u{17e9}'), ('\u{180b}', '\u{180d}'), ('\u{1810}', - '\u{1819}'), ('\u{1820}', '\u{1877}'), ('\u{1880}', '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), - ('\u{1900}', '\u{191e}'), ('\u{1920}', '\u{192b}'), ('\u{1930}', '\u{193b}'), ('\u{1946}', - '\u{196d}'), ('\u{1970}', '\u{1974}'), ('\u{1980}', '\u{19ab}'), ('\u{19b0}', '\u{19c9}'), - ('\u{19d0}', '\u{19da}'), ('\u{1a00}', '\u{1a1b}'), ('\u{1a20}', '\u{1a5e}'), ('\u{1a60}', - '\u{1a7c}'), ('\u{1a7f}', '\u{1a89}'), ('\u{1a90}', '\u{1a99}'), ('\u{1aa7}', '\u{1aa7}'), - ('\u{1ab0}', '\u{1abd}'), ('\u{1b00}', '\u{1b4b}'), ('\u{1b50}', '\u{1b59}'), ('\u{1b6b}', - '\u{1b73}'), ('\u{1b80}', '\u{1bf3}'), ('\u{1c00}', '\u{1c37}'), ('\u{1c40}', '\u{1c49}'), - ('\u{1c4d}', '\u{1c7d}'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1cf6}'), ('\u{1cf8}', - '\u{1cf9}'), ('\u{1d00}', '\u{1df5}'), ('\u{1dfc}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), - ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', - '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), - ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', - '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), - ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{203f}', - '\u{2040}'), ('\u{2054}', '\u{2054}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), - ('\u{2090}', '\u{209c}'), ('\u{20d0}', '\u{20dc}'), ('\u{20e1}', '\u{20e1}'), ('\u{20e5}', - '\u{20f0}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), - ('\u{2115}', '\u{2115}'), ('\u{2118}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', - '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{2139}'), ('\u{213c}', '\u{213f}'), - ('\u{2145}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), ('\u{2c00}', - '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cf3}'), - ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', - '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d7f}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), - ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', - '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), - ('\u{2de0}', '\u{2dff}'), ('\u{3005}', '\u{3007}'), ('\u{3021}', '\u{302f}'), ('\u{3031}', - '\u{3035}'), ('\u{3038}', '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{3099}', '\u{309a}'), - ('\u{309d}', '\u{309f}'), ('\u{30a1}', '\u{30fa}'), ('\u{30fc}', '\u{30ff}'), ('\u{3105}', - '\u{312d}'), ('\u{3131}', '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), - ('\u{3400}', '\u{4db5}'), ('\u{4e00}', '\u{9fd5}'), ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', - '\u{a4fd}'), ('\u{a500}', '\u{a60c}'), ('\u{a610}', '\u{a62b}'), ('\u{a640}', '\u{a66f}'), - ('\u{a674}', '\u{a67d}'), ('\u{a67f}', '\u{a6f1}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', - '\u{a788}'), ('\u{a78b}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b7}'), ('\u{a7f7}', '\u{a827}'), - ('\u{a840}', '\u{a873}'), ('\u{a880}', '\u{a8c4}'), ('\u{a8d0}', '\u{a8d9}'), ('\u{a8e0}', - '\u{a8f7}'), ('\u{a8fb}', '\u{a8fb}'), ('\u{a8fd}', '\u{a8fd}'), ('\u{a900}', '\u{a92d}'), - ('\u{a930}', '\u{a953}'), ('\u{a960}', '\u{a97c}'), ('\u{a980}', '\u{a9c0}'), ('\u{a9cf}', - '\u{a9d9}'), ('\u{a9e0}', '\u{a9fe}'), ('\u{aa00}', '\u{aa36}'), ('\u{aa40}', '\u{aa4d}'), - ('\u{aa50}', '\u{aa59}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', '\u{aac2}'), ('\u{aadb}', - '\u{aadd}'), ('\u{aae0}', '\u{aaef}'), ('\u{aaf2}', '\u{aaf6}'), ('\u{ab01}', '\u{ab06}'), - ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', - '\u{ab2e}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab65}'), ('\u{ab70}', '\u{abea}'), - ('\u{abec}', '\u{abed}'), ('\u{abf0}', '\u{abf9}'), ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', - '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), - ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', '\u{fb28}'), ('\u{fb2a}', - '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), - ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', '\u{fc5d}'), ('\u{fc64}', - '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdf9}'), - ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'), ('\u{fe33}', '\u{fe34}'), ('\u{fe4d}', - '\u{fe4f}'), ('\u{fe71}', '\u{fe71}'), ('\u{fe73}', '\u{fe73}'), ('\u{fe77}', '\u{fe77}'), - ('\u{fe79}', '\u{fe79}'), ('\u{fe7b}', '\u{fe7b}'), ('\u{fe7d}', '\u{fe7d}'), ('\u{fe7f}', - '\u{fefc}'), ('\u{ff10}', '\u{ff19}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff3f}', '\u{ff3f}'), - ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', '\u{ffbe}'), ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}', - '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), ('\u{10000}', '\u{1000b}'), - ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), ('\u{1003c}', '\u{1003d}'), - ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), ('\u{10080}', '\u{100fa}'), - ('\u{10140}', '\u{10174}'), ('\u{101fd}', '\u{101fd}'), ('\u{10280}', '\u{1029c}'), - ('\u{102a0}', '\u{102d0}'), ('\u{102e0}', '\u{102e0}'), ('\u{10300}', '\u{1031f}'), - ('\u{10330}', '\u{1034a}'), ('\u{10350}', '\u{1037a}'), ('\u{10380}', '\u{1039d}'), - ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), - ('\u{10400}', '\u{1049d}'), ('\u{104a0}', '\u{104a9}'), ('\u{10500}', '\u{10527}'), - ('\u{10530}', '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), - ('\u{10760}', '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), - ('\u{1080a}', '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), - ('\u{1083f}', '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', '\u{1089e}'), - ('\u{108e0}', '\u{108f2}'), ('\u{108f4}', '\u{108f5}'), ('\u{10900}', '\u{10915}'), - ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}', '\u{109bf}'), - ('\u{10a00}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '\u{10a13}'), - ('\u{10a15}', '\u{10a17}'), ('\u{10a19}', '\u{10a33}'), ('\u{10a38}', '\u{10a3a}'), - ('\u{10a3f}', '\u{10a3f}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), - ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', '\u{10ae6}'), ('\u{10b00}', '\u{10b35}'), - ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), - ('\u{10c00}', '\u{10c48}'), ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}', '\u{10cf2}'), - ('\u{11000}', '\u{11046}'), ('\u{11066}', '\u{1106f}'), ('\u{1107f}', '\u{110ba}'), - ('\u{110d0}', '\u{110e8}'), ('\u{110f0}', '\u{110f9}'), ('\u{11100}', '\u{11134}'), - ('\u{11136}', '\u{1113f}'), ('\u{11150}', '\u{11173}'), ('\u{11176}', '\u{11176}'), - ('\u{11180}', '\u{111c4}'), ('\u{111ca}', '\u{111cc}'), ('\u{111d0}', '\u{111da}'), - ('\u{111dc}', '\u{111dc}'), ('\u{11200}', '\u{11211}'), ('\u{11213}', '\u{11237}'), - ('\u{11280}', '\u{11286}'), ('\u{11288}', '\u{11288}'), ('\u{1128a}', '\u{1128d}'), - ('\u{1128f}', '\u{1129d}'), ('\u{1129f}', '\u{112a8}'), ('\u{112b0}', '\u{112ea}'), - ('\u{112f0}', '\u{112f9}'), ('\u{11300}', '\u{11303}'), ('\u{11305}', '\u{1130c}'), - ('\u{1130f}', '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), - ('\u{11332}', '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133c}', '\u{11344}'), - ('\u{11347}', '\u{11348}'), ('\u{1134b}', '\u{1134d}'), ('\u{11350}', '\u{11350}'), - ('\u{11357}', '\u{11357}'), ('\u{1135d}', '\u{11363}'), ('\u{11366}', '\u{1136c}'), - ('\u{11370}', '\u{11374}'), ('\u{11480}', '\u{114c5}'), ('\u{114c7}', '\u{114c7}'), - ('\u{114d0}', '\u{114d9}'), ('\u{11580}', '\u{115b5}'), ('\u{115b8}', '\u{115c0}'), - ('\u{115d8}', '\u{115dd}'), ('\u{11600}', '\u{11640}'), ('\u{11644}', '\u{11644}'), - ('\u{11650}', '\u{11659}'), ('\u{11680}', '\u{116b7}'), ('\u{116c0}', '\u{116c9}'), - ('\u{11700}', '\u{11719}'), ('\u{1171d}', '\u{1172b}'), ('\u{11730}', '\u{11739}'), - ('\u{118a0}', '\u{118e9}'), ('\u{118ff}', '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), - ('\u{12000}', '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}', '\u{12543}'), - ('\u{13000}', '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}', '\u{16a38}'), - ('\u{16a40}', '\u{16a5e}'), ('\u{16a60}', '\u{16a69}'), ('\u{16ad0}', '\u{16aed}'), - ('\u{16af0}', '\u{16af4}'), ('\u{16b00}', '\u{16b36}'), ('\u{16b40}', '\u{16b43}'), - ('\u{16b50}', '\u{16b59}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'), - ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f7e}'), ('\u{16f8f}', '\u{16f9f}'), - ('\u{1b000}', '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), - ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1bc9d}', '\u{1bc9e}'), - ('\u{1d165}', '\u{1d169}'), ('\u{1d16d}', '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), - ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), - ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), - ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), - ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), - ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), - ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), - ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), - ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), - ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), - ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), - ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), - ('\u{1d7ce}', '\u{1d7ff}'), ('\u{1da00}', '\u{1da36}'), ('\u{1da3b}', '\u{1da6c}'), - ('\u{1da75}', '\u{1da75}'), ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), - ('\u{1daa1}', '\u{1daaf}'), ('\u{1e800}', '\u{1e8c4}'), ('\u{1e8d0}', '\u{1e8d6}'), - ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), - ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), - ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), - ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), - ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), - ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), - ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), - ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), - ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), - ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), - ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), - ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), - ('\u{2b820}', '\u{2cea1}'), ('\u{2f800}', '\u{2fa1d}'), ('\u{e0100}', '\u{e01ef}') - ]; + pub const XID_Continue_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x03ff000000000000, 0x07fffffe87fffffe, 0x04a0040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, + 0xffffffffffffffff, 0xb8dfffffffffffff, 0xfffffffbffffd7c0, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffcfb, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbffffffffffe00ff, 0x000707ffffff00b6, + 0xffffffff07ff0000, 0xffffc3ffffffffff, 0xffffffffffffffff, 0x9ffffdff9fefffff, + 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x043fffffffffffff + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, 41, 42, 4, 4, + 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 4, 61, 4, 62, 50, 63, 60, 64, 4, 4, 4, 65, 4, 4, 4, 4, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 77, 78, 4, 79, 80, 81, 82, 83, 60, 60, 60, 60, 60, 60, 60, 60, 84, 42, 85, 86, 87, + 4, 88, 89, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 52, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 91, 92, 4, 4, 4, 4, 93, 94, 4, 95, 96, 4, 97, 98, 99, 62, 4, 100, 101, 102, 4, 103, 104, + 105, 4, 106, 107, 108, 4, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 110, 111, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 101, 4, 112, 113, 114, 95, 115, + 4, 116, 4, 4, 117, 118, 119, 120, 121, 122, 4, 123, 124, 125, 126, 127 + ], + r3: &[ + 0x00003fffffffffff, 0x000000000fffffff, 0x001fffff00000000, 0xfffffff800000000, + 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x0003ffcfb080799f, + 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0x0200ffcf00013bbf, + 0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7, + 0xe3fffdfffffddfef, 0x0000ffcf07603ddf, 0xf3effdfffffddfee, 0x0006ffcf40603ddf, + 0xe7fffffffffddfee, 0xfc00ffcf80807ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, + 0x07fffffffffffffe, 0x0000000003ff7fff, 0x3bffecaefef02596, 0x00000000f3ff3f5f, + 0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040, + 0xffffffffffff03ff, 0xffffffff3fffffff, 0xf7ffffffffff20bf, 0xffffffff3d7f3dff, + 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0003fe00e7ffffff, + 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, + 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x001fffff001fdfff, 0x000ddfff000fffff, + 0x000003ff308fffff, 0xffffffff03ff3800, 0x00ffffffffffffff, 0xffff07ffffffffff, + 0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff, + 0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff, + 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x3fffffffffffe3ff, + 0x037ffffffff70000, 0xf03fffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, + 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8000000000000000, 0x8002000000100001, + 0x000000001fff0000, 0x0001ffe21fff0000, 0xf3fffd503f2ffc84, 0xffffffff000043e0, + 0x00000000000001ff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000ff81fffffffff, + 0xffff20bfffffffff, 0x800080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, + 0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe3fffffffffe0, + 0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, 0x0000000000001fff, + 0x3fffffffffff0000, 0x00000fffffff1fff, 0xbff0ffffffffffff, 0x0003ffffffffffff, + 0xfffffffcff800000, 0x00ff3ffffffff9ff, 0xff80000000000000, 0x000000ffffffffff, + 0x28ffffff03ff001f, 0xffff3fffffffffff, 0x1fffffff000fffff, 0x7fffffff03ff8001, + 0x007fffffffffffff, 0xfc7fffff03ff3fff, 0x007cffff38000007, 0xffff7f7f007e7e7e, + 0xffff003ff7ffffff, 0x03ff37ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, + 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0xfffffffffff80000, + 0xfffffff03fffffff, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, + 0x03ff0000000000ff, 0x0018ffff0000ffff, 0xaa8a00000000e000, 0x1fffffffffffffff, + 0x87fffffe03ff0000, 0xffffffc007fffffe, 0x7fffffffffffffff, 0x000000001cfcfcfc + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 12, + 13, 5, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + ], + r5: &[ + 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 4, 14, 15, 4, 4, 2, 2, 2, + 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, + 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 33, 3, 34, 35, 36, 2, 37, 38, 4, 39, 40, 41, + 42, 4, 4, 4, 4, 2, 43, 4, 4, 44, 45, 2, 46, 47, 48, 49, 4, 4, 4, 4, 4, 50, 51, 4, 4, 4, + 4, 4, 4, 4, 52, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 53, 4, 2, 54, 2, 2, 2, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 54, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 56, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, + 2, 2, 2, 52, 57, 4, 58, 16, 59, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 61, 62, 4, + 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 64, 65, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 66, 67, 4, 4, 68, 4, 4, 4, 4, 4, 4, 2, 69, 70, 71, 72, + 73, 2, 2, 2, 2, 74, 75, 76, 77, 78, 79, 4, 4, 4, 4, 4, 4, 4, 4, 80, 81, 82, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 83, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 84, 85, 86, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 87, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, + 2, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4 + ], + r6: &[ + 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, + 0x0000000000000000, 0x001fffffffffffff, 0x2000000000000000, 0xffffffff1fffffff, + 0x000000010001ffff, 0xffff0000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, + 0x00000000003eff0f, 0x000003ff3fffffff, 0xffff00ffffffffff, 0x0000000fffffffff, + 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, + 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, + 0x870ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000007ffffffeff, + 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, + 0x0007ffffffffffff, 0x8000ffc00000007f, 0x03ff01ffffff0000, 0xffdfffffffffffff, + 0x004fffffffff0000, 0x0000000017ff1c1f, 0x00fffffffffbffff, 0xffff01ffbfffbd7f, + 0x03ff07ffffffffff, 0xf3edfdfffff99fef, 0x001f1fcfe081399f, 0x0000000003ff00bf, + 0xff3fffffffffffff, 0x000000003f000001, 0x0000000003ff0011, 0x00ffffffffffffff, + 0x00000000000003ff, 0x03ff0fffe3ffffff, 0xffffffff00000000, 0x800003ffffffffff, + 0x01ffffffffffffff, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, + 0x000000000000007f, 0x000003ff7fffffff, 0x001f3fffffff0000, 0xe0fffff803ff000f, + 0x000000000000ffff, 0x7fffffffffff001f, 0x00000000ffff8000, 0x0000000000000003, + 0x1fff07ffffffffff, 0x0000000063ff01ff, 0xf807e3e000000000, 0x00003c0000000fe7, + 0x000000000000001c, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, + 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, + 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0xffffffffffffcff7, + 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, 0x00000000007f001f, + 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, + 0x00000003ffffffff, 0x000000003fffffff, 0x0000ffffffffffff + ], + }; pub fn XID_Continue(c: char) -> bool { - super::bsearch_range_table(c, XID_Continue_table) + super::trie_lookup_range_table(c, XID_Continue_table) } - pub const XID_Start_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), - ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), - ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', - '\u{2ee}'), ('\u{370}', '\u{374}'), ('\u{376}', '\u{377}'), ('\u{37b}', '\u{37d}'), - ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', - '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), ('\u{3f7}', '\u{481}'), - ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{561}', - '\u{587}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{620}', '\u{64a}'), - ('\u{66e}', '\u{66f}'), ('\u{671}', '\u{6d3}'), ('\u{6d5}', '\u{6d5}'), ('\u{6e5}', - '\u{6e6}'), ('\u{6ee}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), - ('\u{710}', '\u{710}'), ('\u{712}', '\u{72f}'), ('\u{74d}', '\u{7a5}'), ('\u{7b1}', - '\u{7b1}'), ('\u{7ca}', '\u{7ea}'), ('\u{7f4}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), - ('\u{800}', '\u{815}'), ('\u{81a}', '\u{81a}'), ('\u{824}', '\u{824}'), ('\u{828}', - '\u{828}'), ('\u{840}', '\u{858}'), ('\u{8a0}', '\u{8b4}'), ('\u{904}', '\u{939}'), - ('\u{93d}', '\u{93d}'), ('\u{950}', '\u{950}'), ('\u{958}', '\u{961}'), ('\u{971}', - '\u{980}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'), - ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bd}', - '\u{9bd}'), ('\u{9ce}', '\u{9ce}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e1}'), - ('\u{9f0}', '\u{9f1}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), ('\u{a13}', - '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', '\u{a36}'), - ('\u{a38}', '\u{a39}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a72}', - '\u{a74}'), ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), - ('\u{aaa}', '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abd}', - '\u{abd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae1}'), ('\u{af9}', '\u{af9}'), - ('\u{b05}', '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', - '\u{b30}'), ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3d}', '\u{b3d}'), - ('\u{b5c}', '\u{b5d}'), ('\u{b5f}', '\u{b61}'), ('\u{b71}', '\u{b71}'), ('\u{b83}', - '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), - ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', - '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bd0}', '\u{bd0}'), - ('\u{c05}', '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', - '\u{c39}'), ('\u{c3d}', '\u{c3d}'), ('\u{c58}', '\u{c5a}'), ('\u{c60}', '\u{c61}'), - ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', - '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbd}', '\u{cbd}'), ('\u{cde}', '\u{cde}'), - ('\u{ce0}', '\u{ce1}'), ('\u{cf1}', '\u{cf2}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', - '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d3d}'), ('\u{d4e}', '\u{d4e}'), - ('\u{d5f}', '\u{d61}'), ('\u{d7a}', '\u{d7f}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', - '\u{db1}'), ('\u{db3}', '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), - ('\u{e01}', '\u{e30}'), ('\u{e32}', '\u{e32}'), ('\u{e40}', '\u{e46}'), ('\u{e81}', - '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', '\u{e88}'), ('\u{e8a}', '\u{e8a}'), - ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), ('\u{e99}', '\u{e9f}'), ('\u{ea1}', - '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), ('\u{eaa}', '\u{eab}'), - ('\u{ead}', '\u{eb0}'), ('\u{eb2}', '\u{eb2}'), ('\u{ebd}', '\u{ebd}'), ('\u{ec0}', - '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', '\u{f00}'), - ('\u{f40}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f88}', '\u{f8c}'), ('\u{1000}', - '\u{102a}'), ('\u{103f}', '\u{103f}'), ('\u{1050}', '\u{1055}'), ('\u{105a}', '\u{105d}'), - ('\u{1061}', '\u{1061}'), ('\u{1065}', '\u{1066}'), ('\u{106e}', '\u{1070}'), ('\u{1075}', - '\u{1081}'), ('\u{108e}', '\u{108e}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), - ('\u{10cd}', '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', - '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), - ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', - '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), - ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', - '\u{135a}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f5}'), ('\u{13f8}', '\u{13fd}'), - ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', - '\u{16ea}'), ('\u{16ee}', '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1711}'), - ('\u{1720}', '\u{1731}'), ('\u{1740}', '\u{1751}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', - '\u{1770}'), ('\u{1780}', '\u{17b3}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), - ('\u{1820}', '\u{1877}'), ('\u{1880}', '\u{18a8}'), ('\u{18aa}', '\u{18aa}'), ('\u{18b0}', - '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}'), - ('\u{1980}', '\u{19ab}'), ('\u{19b0}', '\u{19c9}'), ('\u{1a00}', '\u{1a16}'), ('\u{1a20}', - '\u{1a54}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1b05}', '\u{1b33}'), ('\u{1b45}', '\u{1b4b}'), - ('\u{1b83}', '\u{1ba0}'), ('\u{1bae}', '\u{1baf}'), ('\u{1bba}', '\u{1be5}'), ('\u{1c00}', - '\u{1c23}'), ('\u{1c4d}', '\u{1c4f}'), ('\u{1c5a}', '\u{1c7d}'), ('\u{1ce9}', '\u{1cec}'), - ('\u{1cee}', '\u{1cf1}'), ('\u{1cf5}', '\u{1cf6}'), ('\u{1d00}', '\u{1dbf}'), ('\u{1e00}', - '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), - ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', - '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), - ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', - '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), - ('\u{1ff6}', '\u{1ffc}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', - '\u{209c}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), - ('\u{2115}', '\u{2115}'), ('\u{2118}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', - '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{2139}'), ('\u{213c}', '\u{213f}'), - ('\u{2145}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), ('\u{2c00}', - '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'), - ('\u{2cf2}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', - '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d80}', '\u{2d96}'), - ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', - '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), - ('\u{2dd8}', '\u{2dde}'), ('\u{3005}', '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3031}', - '\u{3035}'), ('\u{3038}', '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{309d}', '\u{309f}'), - ('\u{30a1}', '\u{30fa}'), ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), ('\u{3131}', - '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), - ('\u{4e00}', '\u{9fd5}'), ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), ('\u{a500}', - '\u{a60c}'), ('\u{a610}', '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a640}', '\u{a66e}'), - ('\u{a67f}', '\u{a69d}'), ('\u{a6a0}', '\u{a6ef}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', - '\u{a788}'), ('\u{a78b}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b7}'), ('\u{a7f7}', '\u{a801}'), - ('\u{a803}', '\u{a805}'), ('\u{a807}', '\u{a80a}'), ('\u{a80c}', '\u{a822}'), ('\u{a840}', - '\u{a873}'), ('\u{a882}', '\u{a8b3}'), ('\u{a8f2}', '\u{a8f7}'), ('\u{a8fb}', '\u{a8fb}'), - ('\u{a8fd}', '\u{a8fd}'), ('\u{a90a}', '\u{a925}'), ('\u{a930}', '\u{a946}'), ('\u{a960}', - '\u{a97c}'), ('\u{a984}', '\u{a9b2}'), ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e0}', '\u{a9e4}'), - ('\u{a9e6}', '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}', '\u{aa28}'), ('\u{aa40}', - '\u{aa42}'), ('\u{aa44}', '\u{aa4b}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', '\u{aa7a}'), - ('\u{aa7e}', '\u{aaaf}'), ('\u{aab1}', '\u{aab1}'), ('\u{aab5}', '\u{aab6}'), ('\u{aab9}', - '\u{aabd}'), ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), ('\u{aadb}', '\u{aadd}'), - ('\u{aae0}', '\u{aaea}'), ('\u{aaf2}', '\u{aaf4}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', - '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), - ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab65}'), ('\u{ab70}', '\u{abe2}'), ('\u{ac00}', - '\u{d7a3}'), ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), - ('\u{fa70}', '\u{fad9}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', - '\u{fb1d}'), ('\u{fb1f}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), - ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', - '\u{fbb1}'), ('\u{fbd3}', '\u{fc5d}'), ('\u{fc64}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), - ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdf9}'), ('\u{fe71}', '\u{fe71}'), ('\u{fe73}', - '\u{fe73}'), ('\u{fe77}', '\u{fe77}'), ('\u{fe79}', '\u{fe79}'), ('\u{fe7b}', '\u{fe7b}'), - ('\u{fe7d}', '\u{fe7d}'), ('\u{fe7f}', '\u{fefc}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', - '\u{ff5a}'), ('\u{ff66}', '\u{ff9d}'), ('\u{ffa0}', '\u{ffbe}'), ('\u{ffc2}', '\u{ffc7}'), - ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), ('\u{10000}', - '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), ('\u{1003c}', - '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), ('\u{10080}', - '\u{100fa}'), ('\u{10140}', '\u{10174}'), ('\u{10280}', '\u{1029c}'), ('\u{102a0}', - '\u{102d0}'), ('\u{10300}', '\u{1031f}'), ('\u{10330}', '\u{1034a}'), ('\u{10350}', - '\u{10375}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', - '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), ('\u{10400}', '\u{1049d}'), ('\u{10500}', - '\u{10527}'), ('\u{10530}', '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', - '\u{10755}'), ('\u{10760}', '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', - '\u{10808}'), ('\u{1080a}', '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', - '\u{1083c}'), ('\u{1083f}', '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', - '\u{1089e}'), ('\u{108e0}', '\u{108f2}'), ('\u{108f4}', '\u{108f5}'), ('\u{10900}', - '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}', - '\u{109bf}'), ('\u{10a00}', '\u{10a00}'), ('\u{10a10}', '\u{10a13}'), ('\u{10a15}', - '\u{10a17}'), ('\u{10a19}', '\u{10a33}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', - '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', '\u{10ae4}'), ('\u{10b00}', - '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', - '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}', - '\u{10cf2}'), ('\u{11003}', '\u{11037}'), ('\u{11083}', '\u{110af}'), ('\u{110d0}', - '\u{110e8}'), ('\u{11103}', '\u{11126}'), ('\u{11150}', '\u{11172}'), ('\u{11176}', - '\u{11176}'), ('\u{11183}', '\u{111b2}'), ('\u{111c1}', '\u{111c4}'), ('\u{111da}', - '\u{111da}'), ('\u{111dc}', '\u{111dc}'), ('\u{11200}', '\u{11211}'), ('\u{11213}', - '\u{1122b}'), ('\u{11280}', '\u{11286}'), ('\u{11288}', '\u{11288}'), ('\u{1128a}', - '\u{1128d}'), ('\u{1128f}', '\u{1129d}'), ('\u{1129f}', '\u{112a8}'), ('\u{112b0}', - '\u{112de}'), ('\u{11305}', '\u{1130c}'), ('\u{1130f}', '\u{11310}'), ('\u{11313}', - '\u{11328}'), ('\u{1132a}', '\u{11330}'), ('\u{11332}', '\u{11333}'), ('\u{11335}', - '\u{11339}'), ('\u{1133d}', '\u{1133d}'), ('\u{11350}', '\u{11350}'), ('\u{1135d}', - '\u{11361}'), ('\u{11480}', '\u{114af}'), ('\u{114c4}', '\u{114c5}'), ('\u{114c7}', - '\u{114c7}'), ('\u{11580}', '\u{115ae}'), ('\u{115d8}', '\u{115db}'), ('\u{11600}', - '\u{1162f}'), ('\u{11644}', '\u{11644}'), ('\u{11680}', '\u{116aa}'), ('\u{11700}', - '\u{11719}'), ('\u{118a0}', '\u{118df}'), ('\u{118ff}', '\u{118ff}'), ('\u{11ac0}', - '\u{11af8}'), ('\u{12000}', '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}', - '\u{12543}'), ('\u{13000}', '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}', - '\u{16a38}'), ('\u{16a40}', '\u{16a5e}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16b00}', - '\u{16b2f}'), ('\u{16b40}', '\u{16b43}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', - '\u{16b8f}'), ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f50}'), ('\u{16f93}', - '\u{16f9f}'), ('\u{1b000}', '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', - '\u{1bc7c}'), ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1d400}', - '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', - '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', - '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', - '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', - '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', - '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', - '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', - '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', - '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', - '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1e800}', - '\u{1e8c4}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', - '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', - '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', - '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', - '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', - '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', - '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', - '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', - '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', - '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', - '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', - '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', - '\u{2b81d}'), ('\u{2b820}', '\u{2cea1}'), ('\u{2f800}', '\u{2fa1d}') - ]; + pub const XID_Start_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, + 0x0000000000000000, 0xb8df000000000000, 0xfffffffbffffd740, 0xffbfffffffffffff, + 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, + 0xfffeffffffffffff, 0xfffffffe027fffff, 0x00000000000000ff, 0x000707ffffff0000, + 0xffffffff00000000, 0xfffec000000007ff, 0xffffffffffffffff, 0x9c00c060002fffff, + 0x0000fffffffd0000, 0xffffffffffffe000, 0x0002003fffffffff, 0x043007fffffffc00 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 23, 25, + 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 3, 67, 34, 34, 34, 3, 34, 34, 34, 34, 68, 69, + 70, 71, 3, 72, 73, 3, 74, 75, 76, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 77, 78, 34, 79, 80, + 81, 82, 83, 3, 3, 3, 3, 3, 3, 3, 3, 84, 42, 85, 86, 87, 34, 88, 89, 3, 3, 3, 3, 3, 3, 3, + 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 53, 3, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 92, 34, 34, 34, 34, 93, 94, 95, 96, 97, + 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 34, + 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 114, + 115, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 116, 34, 117, + 118, 119, 120, 121, 34, 122, 34, 34, 123, 124, 125, 126, 3, 127, 34, 128, 129, 130, 131, + 132 + ], + r3: &[ + 0x00000110043fffff, 0x0000000001ffffff, 0x001fffff00000000, 0x0000000000000000, + 0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x00030003b0004000, + 0x036dfdfffff987e0, 0x001c00005e000000, 0x23edfdfffffbbfe0, 0x0200000300010000, + 0x23edfdfffff99fe0, 0x00020003b0000000, 0x03ffc718d63dc7e8, 0x0000000000010000, + 0x23fffdfffffddfe0, 0x0000000307000000, 0x23effdfffffddfe0, 0x0006000340000000, + 0x27fffffffffddfe0, 0xfc00000380004000, 0x2ffbfffffc7fffe0, 0x000000000000007f, + 0x0005fffffffffffe, 0x2005ecaefef02596, 0x00000000f000005f, 0x0000000000000001, + 0x00001ffffffffeff, 0x0000000000001f00, 0x800007ffffffffff, 0xffe1c0623c3f0000, + 0xffffffff00004003, 0xf7ffffffffff20bf, 0xffffffffffffffff, 0xffffffff3d7f3dff, + 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0000000007ffffff, + 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, + 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x0003ffff0003dfff, 0x0001dfff0003ffff, + 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x00ffffffffffffff, + 0xffff05ffffffffff, 0x003fffffffffffff, 0x000000007fffffff, 0x001f3fffffff0000, + 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff007fffff, 0x00000000001fffff, + 0x0000008000000000, 0x000fffffffffffe0, 0x0000000000000fe0, 0xfc00c001fffffff8, + 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0x0063de0000000000, + 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, + 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84, 0xffffffff000043e0, + 0x00000000000001ff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, + 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0x000000007f7f7f7f, + 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe3fffffffffe0, + 0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, 0x0000000000001fff, + 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, 0xffffffff3fffffff, + 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff3ffffffff9ff, 0xff80000000000000, + 0x00000007fffff7bb, 0x000ffffffffffffc, 0x28fc000000000000, 0xffff003ffffffc00, + 0x1fffffff0000007f, 0x0007fffffffffff0, 0x7c00ffdf00008000, 0x000001ffffffffff, + 0xc47fffff00000ff7, 0x3e62ffffffffffff, 0x001c07ff38000005, 0xffff7f7f007e7e7e, + 0xffff003ff7ffffff, 0x00000007ffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, + 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffa0f8007f, 0xffffffffffffffdb, + 0x0003ffffffffffff, 0xfffffffffff80000, 0xfffffff03fffffff, 0x3fffffffffffffff, + 0xffffffffffff0000, 0xfffffffffffcffff, 0x03ff0000000000ff, 0xaa8a000000000000, + 0x1fffffffffffffff, 0x07fffffe00000000, 0xffffffc007fffffe, 0x7fffffff3fffffff, + 0x000000001cfcfcfc + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, + 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 12, + 13, 5, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + ], + r5: &[ + 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 4, 13, 14, 4, 4, 2, 2, 2, 2, + 15, 16, 4, 4, 17, 18, 19, 20, 21, 4, 22, 4, 23, 24, 25, 26, 27, 28, 29, 4, 2, 30, 31, + 31, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 32, 4, 33, 34, 35, 36, 37, 38, 39, 4, 40, 19, + 41, 42, 4, 4, 4, 4, 43, 44, 4, 4, 45, 46, 43, 47, 48, 4, 49, 4, 4, 4, 4, 4, 50, 51, 4, + 4, 4, 4, 4, 4, 4, 52, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 49, 4, 2, 45, 2, 2, 2, 53, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 54, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, + 2, 2, 2, 2, 2, 52, 19, 4, 55, 43, 56, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 58, + 59, 4, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 61, 62, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 63, 64, 65, + 66, 67, 2, 2, 2, 2, 68, 69, 70, 71, 72, 73, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 74, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 75, 76, 77, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 78, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 79, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, + 2, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + ], + r6: &[ + 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, + 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, + 0xffff0000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, + 0x000000003fffffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, + 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, + 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, 0x000ffffffeef0001, + 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, 0x003fffffffffffff, + 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, 0x0007ffffffffffff, + 0x00fffffffffffff8, 0x0000fffffffffff8, 0x000001ffffff0000, 0x0000007ffffffff8, + 0x0047ffffffff0000, 0x0007fffffffffff8, 0x000000001400001e, 0x00000ffffffbffff, + 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000, 0x0000ffffffffffff, + 0x00000000000000b0, 0x00007fffffffffff, 0x000000000f000000, 0x0000000000000010, + 0x000007ffffffffff, 0x0000000003ffffff, 0xffffffff00000000, 0x80000000ffffffff, + 0x01ffffffffffffff, 0x000000000000000f, 0x000000000000007f, 0x00003fffffff0000, + 0xe0fffff80000000f, 0x000000000000ffff, 0x000000000001001f, 0x00000000fff80000, + 0x0000000000000003, 0x1fff07ffffffffff, 0x0000000003ff01ff, 0xffffffffffdfffff, + 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, + 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, + 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef, + 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0x00000003ffffffff + ], + }; pub fn XID_Start(c: char) -> bool { - super::bsearch_range_table(c, XID_Start_table) + super::trie_lookup_range_table(c, XID_Start_table) } } pub mod property { - pub const Pattern_White_Space_table: &'static [(char, char)] = &[ - ('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{200e}', '\u{200f}'), - ('\u{2028}', '\u{2029}') - ]; + pub const Pattern_White_Space_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000100003e00, 0x0000000000000000, 0x0000000000000020, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ], + r3: &[ + 0x0000000000000000, 0x000003000000c000 + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000 + ], + }; pub fn Pattern_White_Space(c: char) -> bool { - super::bsearch_range_table(c, Pattern_White_Space_table) + super::trie_lookup_range_table(c, Pattern_White_Space_table) } - pub const White_Space_table: &'static [(char, char)] = &[ - ('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{a0}', '\u{a0}'), - ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'), ('\u{2028}', '\u{2029}'), ('\u{202f}', - '\u{202f}'), ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}') - ]; + pub const White_Space_table: &'static super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000100003e00, 0x0000000000000000, 0x0000000100000020, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 + ], + r2: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 + ], + r3: &[ + 0x0000000000000000, 0x0000000000000001, 0x00008300000007ff, 0x0000000080000000 + ], + r4: [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + ], + r6: &[ + 0x0000000000000000 + ], + }; pub fn White_Space(c: char) -> bool { - super::bsearch_range_table(c, White_Space_table) + super::trie_lookup_range_table(c, White_Space_table) } } From 045253a8c0a30998db69658f4693829a08dc6dfb Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Tue, 19 Apr 2016 12:52:23 -0700 Subject: [PATCH 003/179] Fix wrong shift in trie_lookup_range_table Somehow got in my head that >> 8 was the right shift for a chunk of 64. Oops, sorry. --- src/etc/unicode.py | 2 +- src/librustc_unicode/tables.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 406f5380d469..2b0f8d971f51 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -330,7 +330,7 @@ def emit_trie_lookup_range_table(f): fn trie_lookup_range_table(c: char, r: &'static BoolTrie) -> bool { let c = c as usize; if c < 0x800 { - trie_range_leaf(c, r.r1[c >> 8]) + trie_range_leaf(c, r.r1[c >> 6]) } else if c < 0x10000 { let child = r.r2[c >> 6]; trie_range_leaf(c, r.r3[child as usize]) diff --git a/src/librustc_unicode/tables.rs b/src/librustc_unicode/tables.rs index a3afa3b56ec9..6c992369cd45 100644 --- a/src/librustc_unicode/tables.rs +++ b/src/librustc_unicode/tables.rs @@ -37,7 +37,7 @@ fn trie_range_leaf(c: usize, bitmap_chunk: u64) -> bool { fn trie_lookup_range_table(c: char, r: &'static BoolTrie) -> bool { let c = c as usize; if c < 0x800 { - trie_range_leaf(c, r.r1[c >> 8]) + trie_range_leaf(c, r.r1[c >> 6]) } else if c < 0x10000 { let child = r.r2[c >> 6]; trie_range_leaf(c, r.r3[child as usize]) From 763767641baf2debe94d0deb95c4b5149118b2f9 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Wed, 20 Apr 2016 21:56:35 -0700 Subject: [PATCH 004/179] Add comment, reduce storage requirements Adds a comment which explains the trie structure, and also does a little arithmetic on lookup (no measurable impact, looks like modern CPUs do this arithmetic in parallel with the memory lookup to find the node) to save a bit of space. As a result, the memory impact of the compiled tables is within a couple hundred bytes of the old bsearch-range structure. --- src/etc/unicode.py | 39 ++++- src/librustc_unicode/tables.rs | 310 ++++++++++++++++----------------- 2 files changed, 182 insertions(+), 167 deletions(-) diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 2b0f8d971f51..a99770f22614 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -25,6 +25,9 @@ import fileinput, re, os, sys, operator +bytes_old = 0 +bytes_new = 0 + preamble = '''// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. @@ -309,16 +312,36 @@ def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True, def emit_trie_lookup_range_table(f): f.write(""" + +// BoolTrie is a trie for representing a set of Unicode codepoints. It is +// implemented with postfix compression (sharing of identical child nodes), +// which gives both compact size and fast lookup. +// +// The space of Unicode codepoints is divided into 3 subareas, each +// represented by a trie with different depth. In the first (0..0x800), there +// is no trie structure at all; each u64 entry corresponds to a bitvector +// effectively holding 64 bool values. +// +// In the second (0x800..0x10000), each child of the root node represents a +// 64-wide subrange, but instead of storing the full 64-bit value of the leaf, +// the trie stores an 8-bit index into a shared table of leaf values. This +// exploits the fact that in reasonable sets, many such leaves can be shared. +// +// In the third (0x10000..0x110000), each child of the root node represents a +// 4096-wide subrange, and the trie stores an 8-bit index into a 64-byte slice +// of a child tree. Each of these 64 bytes represents an index into the table +// of shared 64-bit leaf values. This exploits the sparse structure in the +// non-BMP range of most Unicode sets. pub struct BoolTrie { // 0..0x800 (corresponding to 1 and 2 byte utf-8 sequences) r1: [u64; 32], // leaves // 0x800..0x10000 (corresponding to 3 byte utf-8 sequences) - r2: [u8; 1024], // first level + r2: [u8; 992], // first level r3: &'static [u64], // leaves // 0x10000..0x110000 (corresponding to 4 byte utf-8 sequences) - r4: [u8; 272], // first level + r4: [u8; 256], // first level r5: &'static [u8], // second level r6: &'static [u64], // leaves } @@ -332,10 +355,10 @@ def emit_trie_lookup_range_table(f): if c < 0x800 { trie_range_leaf(c, r.r1[c >> 6]) } else if c < 0x10000 { - let child = r.r2[c >> 6]; + let child = r.r2[(c >> 6) - 0x20]; trie_range_leaf(c, r.r3[child as usize]) } else { - let child = r.r4[c >> 12]; + let child = r.r4[(c >> 12) - 0x10]; let leaf = r.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; trie_range_leaf(c, r.r6[leaf as usize]) } @@ -356,6 +379,8 @@ def compute_trie(rawdata, chunksize): return (root, child_data) def emit_bool_trie(f, name, t_data, is_pub=True): + global bytes_old, bytes_new + bytes_old += 8 * len(t_data) CHUNK = 64 rawdata = [False] * 0x110000; for (lo, hi) in t_data: @@ -383,7 +408,7 @@ def emit_bool_trie(f, name, t_data, is_pub=True): # 0x800..0x10000 trie (r2, r3) = compute_trie(chunks[0x800 / CHUNK : 0x10000 / CHUNK], 64 / CHUNK) f.write(" r2: [\n") - data = ','.join(str(node) for node in [255] * 32 + r2) + data = ','.join(str(node) for node in r2) format_table_content(f, data, 12) f.write("\n ],\n") f.write(" r3: &[\n") @@ -395,7 +420,7 @@ def emit_bool_trie(f, name, t_data, is_pub=True): (mid, r6) = compute_trie(chunks[0x10000 / CHUNK : 0x110000 / CHUNK], 64 / CHUNK) (r4, r5) = compute_trie(mid, 64) f.write(" r4: [\n") - data = ','.join(str(node) for node in [255] * 16 + r4) + data = ','.join(str(node) for node in r4) format_table_content(f, data, 12) f.write("\n ],\n") f.write(" r5: &[\n") @@ -408,6 +433,7 @@ def emit_bool_trie(f, name, t_data, is_pub=True): f.write("\n ],\n") f.write(" };\n\n") + bytes_new += 256 + 992 + 256 + 8 * len(r3) + len(r5) + 8 * len(r6) def emit_property_module(f, mod, tbl, emit): f.write("pub mod %s {\n" % mod) @@ -517,3 +543,4 @@ def emit_norm_module(f, canon, compat, combine, norm_props): # normalizations and conversions module emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props) emit_conversions_module(rf, to_upper, to_lower, to_title) + #print 'bytes before = %d, bytes after = %d' % (bytes_old, bytes_new) diff --git a/src/librustc_unicode/tables.rs b/src/librustc_unicode/tables.rs index 6c992369cd45..43e7c26fd721 100644 --- a/src/librustc_unicode/tables.rs +++ b/src/librustc_unicode/tables.rs @@ -16,16 +16,36 @@ /// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on. pub const UNICODE_VERSION: (u64, u64, u64) = (8, 0, 0); + +// BoolTrie is a trie for representing a set of Unicode codepoints. It is +// implemented with postfix compression (sharing of identical child nodes), +// which gives both compact size and fast lookup. +// +// The space of Unicode codepoints is divided into 3 subareas, each +// represented by a trie with different depth. In the first (0..0x800), there +// is no trie structure at all; each u64 entry corresponds to a bitvector +// effectively holding 64 bool values. +// +// In the second (0x800..0x10000), each child of the root node represents a +// 64-wide subrange, but instead of storing the full 64-bit value of the leaf, +// the trie stores an 8-bit index into a shared table of leaf values. This +// exploits the fact that in reasonable sets, many such leaves can be shared. +// +// In the third (0x10000..0x110000), each child of the root node represents a +// 4096-wide subrange, and the trie stores an 8-bit index into a 64-byte slice +// of a child tree. Each of these 64 bytes represents an index into the table +// of shared 64-bit leaf values. This exploits the sparse structure in the +// non-BMP range of most Unicode sets. pub struct BoolTrie { // 0..0x800 (corresponding to 1 and 2 byte utf-8 sequences) r1: [u64; 32], // leaves // 0x800..0x10000 (corresponding to 3 byte utf-8 sequences) - r2: [u8; 1024], // first level + r2: [u8; 992], // first level r3: &'static [u64], // leaves // 0x10000..0x110000 (corresponding to 4 byte utf-8 sequences) - r4: [u8; 272], // first level + r4: [u8; 256], // first level r5: &'static [u8], // second level r6: &'static [u64], // leaves } @@ -39,10 +59,10 @@ fn trie_lookup_range_table(c: char, r: &'static BoolTrie) -> bool { if c < 0x800 { trie_range_leaf(c, r.r1[c >> 6]) } else if c < 0x10000 { - let child = r.r2[c >> 6]; + let child = r.r2[(c >> 6) - 0x20]; trie_range_leaf(c, r.r3[child as usize]) } else { - let child = r.r4[c >> 12]; + let child = r.r4[(c >> 12) - 0x10]; let leaf = r.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)]; trie_range_leaf(c, r.r6[leaf as usize]) } @@ -61,8 +81,6 @@ pub mod general_category { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -97,13 +115,12 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 + 0, 0, 0, 0, 0, 0 ], r3: &[ 0x0000000000000000 ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -112,7 +129,7 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -140,14 +157,12 @@ pub mod general_category { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00000000000003ff ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3, 0, 0, 0, 0, - 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, - 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3, + 0, 0, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 0, 0, 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -163,8 +178,8 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -175,8 +190,8 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, - 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0 ], r3: &[ 0x0000000000000000, 0x0000ffc000000000, 0x0000000003ff0000, 0x000003ff00000000, @@ -185,8 +200,7 @@ pub mod general_category { 0x03ff000003ff0000 ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -194,7 +208,7 @@ pub mod general_category { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ], r5: &[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -239,21 +253,19 @@ pub mod derived_property { 0xffffffffffff0000, 0xffffffffffffe000, 0x0003ffffffffffff, 0x043007fffffffc00 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 36, 36, 36, 36, 36, 36, 36, 36, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 31, 63, 64, 65, 66, 55, 67, 31, 68, 36, 36, 36, 69, 36, 36, 36, 36, 70, - 71, 72, 73, 31, 74, 75, 31, 76, 77, 78, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 79, - 80, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 81, 82, 36, 83, 84, 85, 86, 87, 88, 31, 31, 31, 31, 31, 31, - 31, 89, 44, 90, 91, 92, 36, 93, 94, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, 36, 36, 36, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 36, 36, 36, 36, 36, 36, 36, 36, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 31, 63, 64, 65, 66, 55, 67, 31, 68, 36, 36, 36, 69, 36, 36, + 36, 36, 70, 71, 72, 73, 31, 74, 75, 31, 76, 77, 78, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 79, 80, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 81, 82, 36, 83, 84, 85, 86, 87, 88, 31, 31, 31, + 31, 31, 31, 31, 89, 44, 90, 91, 92, 36, 93, 94, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 55, 31, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 55, 31, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -268,9 +280,9 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, 103, 104, - 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 117, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, + 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 117, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -278,15 +290,15 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 118, 119, 31, 31, 31, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 118, 119, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, 36, - 36, 36, 120, 36, 121, 122, 123, 124, 125, 36, 36, 36, 36, 126, 127, 128, 129, 31, 130, - 36, 131, 132, 133, 113, 134 + 36, 36, 36, 36, 36, 120, 36, 121, 122, 123, 124, 125, 36, 36, 36, 36, 126, 127, 128, + 129, 31, 130, 36, 131, 132, 133, 113, 134 ], r3: &[ 0x00001ffffcffffff, 0x0000000001ffffff, 0x001fffff00000000, 0xffff03f800000000, @@ -325,16 +337,15 @@ pub mod derived_property { 0x07fffffe00000000, 0xffffffc007fffffe, 0x000000001cfcfcfc ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, - 14, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 0, 1, 2, 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 12, 13, 14, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ], r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 4, 13, 14, 4, 4, 2, 2, 2, 2, @@ -416,15 +427,13 @@ pub mod derived_property { 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x043ff80000000000 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 38, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, 44, 45, 46, - 47, 48, 49, 2, 50, 51, 52, 53, 54, 2, 2, 2, 2, 2, 2, 55, 56, 57, 58, 59, 60, 2, 2, 2, 2, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 38, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, + 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, 2, 2, 2, 2, 2, 2, 55, 56, 57, 58, 59, 60, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 62, 2, 63, 2, 64, 65, 2, 2, 2, 2, 2, 2, 2, - 66, 2, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 62, 2, 63, 2, 64, 65, 2, 2, 2, 2, + 2, 2, 2, 66, 2, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -439,9 +448,9 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 49, 2, 2, 2, 2, 70, 71, 72, 73, 74, 75, 76, 77, 78, 2, 2, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 2, 88, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 49, 2, 2, 2, 2, 70, 71, 72, 73, 74, 75, 76, 77, 78, 2, 2, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 2, 88, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -452,8 +461,8 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 94, 2, 95, 96, 97, - 98, 99 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 94, 2, 95, + 96, 97, 98, 99 ], r3: &[ 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffff800000000, @@ -483,16 +492,15 @@ pub mod derived_property { 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, 0x0e00000800000000 ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + 2, 2, 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -548,14 +556,12 @@ pub mod derived_property { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, - 4, 5, 6, 7, 8, 0, 9, 10, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 4, - 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, + 0, 4, 4, 4, 4, 5, 6, 7, 8, 0, 9, 10, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 17, 4, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -571,8 +577,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, 22, 4, 23, - 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, + 22, 4, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -583,8 +589,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 28, 29, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 28, 29, 0, 0 ], r3: &[ 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x3f3fffffffffffff, @@ -597,8 +603,7 @@ pub mod derived_property { 0x07fffffe00000000, 0x0000000007fffffe ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -606,7 +611,7 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -647,14 +652,12 @@ pub mod derived_property { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 3, 3, 4, - 3, 5, 6, 7, 8, 0, 9, 10, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 3, - 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, + 0, 3, 3, 4, 3, 5, 6, 7, 8, 0, 9, 10, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 16, 3, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -670,8 +673,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 21, 22, 23, - 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 25, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, + 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 25, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -682,8 +685,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 27, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 27, 0, 0 ], r3: &[ 0x0000000000000000, 0x3f00000000000000, 0xffffffffffffffff, 0xaaaaaaaaaaaaaaaa, @@ -695,8 +698,7 @@ pub mod derived_property { 0x0700000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, 0x0000000007fffffe ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -704,7 +706,7 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -743,15 +745,12 @@ pub mod derived_property { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 5, - 4, 6, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 4, - 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, + 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 16, 4, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -766,8 +765,9 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 0, + 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -779,7 +779,7 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 23, 0, 0, 0 + 0, 0, 0, 0, 0, 23, 0, 0, 0 ], r3: &[ 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x003fffffffffffff, @@ -790,8 +790,7 @@ pub mod derived_property { 0x5554555400000000, 0x6a00555555555555, 0x005f3d5555452855, 0x07fffffe00000000 ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -799,7 +798,7 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -841,20 +840,18 @@ pub mod derived_property { 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x043fffffffffffff ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, 41, 42, 4, 4, - 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 4, 61, 4, 62, 50, 63, 60, 64, 4, 4, 4, 65, 4, 4, 4, 4, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, + 41, 42, 4, 4, 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 4, 61, 4, 62, 50, 63, 60, 64, 4, 4, 4, 65, 4, 4, 4, 4, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 77, 78, 4, 79, 80, 81, 82, 83, 60, 60, 60, 60, 60, 60, 60, 60, 84, 42, 85, 86, 87, - 4, 88, 89, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 60, 60, 60, 60, 60, 77, 78, 4, 79, 80, 81, 82, 83, 60, 60, 60, 60, 60, 60, 60, 60, 84, + 42, 85, 86, 87, 4, 88, 89, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 52, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 52, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, @@ -865,22 +862,23 @@ pub mod derived_property { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 91, 92, 4, 4, 4, 4, 93, 94, 4, 95, 96, 4, 97, 98, 99, 62, 4, 100, 101, 102, 4, 103, 104, - 105, 4, 106, 107, 108, 4, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 91, 92, 4, 4, 4, 4, 93, 94, 4, 95, 96, 4, 97, 98, 99, 62, 4, 100, 101, + 102, 4, 103, 104, 105, 4, 106, 107, 108, 4, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 110, 111, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 110, 111, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 101, 4, 112, 113, 114, 95, 115, - 4, 116, 4, 4, 117, 118, 119, 120, 121, 122, 4, 123, 124, 125, 126, 127 + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 101, 4, 112, + 113, 114, 95, 115, 4, 116, 4, 4, 117, 118, 119, 120, 121, 122, 4, 123, 124, 125, 126, + 127 ], r3: &[ 0x00003fffffffffff, 0x000000000fffffff, 0x001fffff00000000, 0xfffffff800000000, @@ -917,16 +915,15 @@ pub mod derived_property { 0x87fffffe03ff0000, 0xffffffc007fffffe, 0x7fffffffffffffff, 0x000000001cfcfcfc ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 12, - 13, 5, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 0, 1, 2, 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 12, 13, 5, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ], r5: &[ 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 4, 14, 15, 4, 4, 2, 2, 2, @@ -1010,20 +1007,19 @@ pub mod derived_property { 0x0000fffffffd0000, 0xffffffffffffe000, 0x0002003fffffffff, 0x043007fffffffc00 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 23, 25, - 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 3, 67, 34, 34, 34, 3, 34, 34, 34, 34, 68, 69, - 70, 71, 3, 72, 73, 3, 74, 75, 76, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 77, 78, 34, 79, 80, - 81, 82, 83, 3, 3, 3, 3, 3, 3, 3, 3, 84, 42, 85, 86, 87, 34, 88, 89, 3, 3, 3, 3, 3, 3, 3, - 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 23, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 3, 67, 34, 34, 34, 3, 34, 34, 34, + 34, 68, 69, 70, 71, 3, 72, 73, 3, 74, 75, 76, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 77, 78, + 34, 79, 80, 81, 82, 83, 3, 3, 3, 3, 3, 3, 3, 3, 84, 42, 85, 86, 87, 34, 88, 89, 3, 3, 3, + 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 53, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 53, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, @@ -1037,25 +1033,24 @@ pub mod derived_property { 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 92, 34, 34, 34, 34, 93, 94, + 95, 96, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 34, 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 92, 34, 34, 34, 34, 93, 94, 95, 96, 97, - 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 34, - 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 114, - 115, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 34, 34, 114, 115, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 116, 34, 117, - 118, 119, 120, 121, 34, 122, 34, 34, 123, 124, 125, 126, 3, 127, 34, 128, 129, 130, 131, - 132 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, + 116, 34, 117, 118, 119, 120, 121, 34, 122, 34, 34, 123, 124, 125, 126, 3, 127, 34, 128, + 129, 130, 131, 132 ], r3: &[ 0x00000110043fffff, 0x0000000001ffffff, 0x001fffff00000000, 0x0000000000000000, @@ -1094,16 +1089,15 @@ pub mod derived_property { 0x000000001cfcfcfc ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, - 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 12, - 13, 5, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 0, 1, 2, 3, 4, 5, 6, 5, 5, 5, 5, 7, 5, 8, 9, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 12, 13, 5, 5, 14, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ], r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 4, 13, 14, 4, 4, 2, 2, 2, 2, @@ -1184,12 +1178,10 @@ pub mod property { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1220,13 +1212,12 @@ pub mod property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 + 0, 0, 0, 0, 0, 0 ], r3: &[ 0x0000000000000000, 0x000003000000c000 ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1235,7 +1226,7 @@ pub mod property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1263,14 +1254,12 @@ pub mod property { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1299,13 +1288,12 @@ pub mod property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 + 0, 0, 0, 0, 0, 0 ], r3: &[ 0x0000000000000000, 0x0000000000000001, 0x00008300000007ff, 0x0000000080000000 ], r4: [ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1314,7 +1302,7 @@ pub mod property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, From e9354091d26e9e0c5122284a158ec14f5563a250 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 15:12:52 +0200 Subject: [PATCH 005/179] fix bug in `debug!` output from `rustc::middle::dataflow` (bug was cut/pasted into `rustc_borrowck::bitslice`, so I fixed it there as well.) --- src/librustc/middle/dataflow.rs | 4 ++-- src/librustc_borrowck/bitslice.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 41b27a48b29f..4d01b59001c5 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -660,8 +660,8 @@ fn set_bit(words: &mut [usize], bit: usize) -> bool { } fn bit_str(bit: usize) -> String { - let byte = bit >> 8; - let lobits = 1 << (bit & 0xFF); + let byte = bit >> 3; + let lobits = 1 << (bit & 0b111); format!("[{}:{}-{:02x}]", bit, byte, lobits) } diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_borrowck/bitslice.rs index a4aa7ae15744..0454b0f3e7cc 100644 --- a/src/librustc_borrowck/bitslice.rs +++ b/src/librustc_borrowck/bitslice.rs @@ -73,8 +73,8 @@ fn bit_lookup(bit: usize) -> BitLookup { fn bit_str(bit: usize) -> String { - let byte = bit >> 8; - let lobits = 1 << (bit & 0xFF); + let byte = bit >> 3; + let lobits = 1 << (bit & 0b111); format!("[{}:{}-{:02x}]", bit, byte, lobits) } From eb080c500bc1404a220ecd1df0e9d16d0365c7ba Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 15:57:49 +0200 Subject: [PATCH 006/179] fixes to `librustc_borrowck::bitslice::bits_to_string`, used for graphviz printing. --- src/librustc_borrowck/bitslice.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_borrowck/bitslice.rs index 0454b0f3e7cc..ca672e808843 100644 --- a/src/librustc_borrowck/bitslice.rs +++ b/src/librustc_borrowck/bitslice.rs @@ -78,25 +78,29 @@ fn bit_str(bit: usize) -> String { format!("[{}:{}-{:02x}]", bit, byte, lobits) } -pub fn bits_to_string(words: &[usize], bytes: usize) -> String { +pub fn bits_to_string(words: &[usize], bits: usize) -> String { let mut result = String::new(); let mut sep = '['; // Note: this is a little endian printout of bytes. + // i tracks how many bits we have printed so far. let mut i = 0; for &word in words.iter() { let mut v = word; - for _ in 0..mem::size_of::() { - let byte = v & 0xFF; - if i >= bytes { - assert!(byte == 0); - } else { - result.push(sep); - result.push_str(&format!("{:02x}", byte)); - } + loop { // for each byte in `v`: + let remain = bits - i; + // If less than a byte remains, then mask just that many bits. + let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; + assert!(mask <= 0xFF); + let byte = v & mask; + + result.push(sep); + result.push_str(&format!("{:02x}", byte)); + + if remain <= 8 { break; } v >>= 8; - i += 1; + i += 8; sep = '-'; } } From 698750f3754a15457b9eccc9a2eac412ccf010ac Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 16:06:18 +0200 Subject: [PATCH 007/179] `rustc_mir::pretty`: factor out scope entry/exit annotation computation. --- src/librustc_mir/pretty.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index fb29cbd5fa8a..f11d0c84ec29 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -106,12 +106,9 @@ enum Annotation { ExitScope(ScopeId), } -pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - w: &mut Write, - auxiliary: Option<&ScopeAuxiliaryVec>) - -> io::Result<()> { +fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>) + -> FnvHashMap> +{ // compute scope/entry exit annotations let mut annotations = FnvHashMap(); if let Some(auxiliary) = auxiliary { @@ -129,7 +126,16 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } } + return annotations; +} +pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + w: &mut Write, + auxiliary: Option<&ScopeAuxiliaryVec>) + -> io::Result<()> { + let annotations = scope_entry_exit_annotations(auxiliary); write_mir_intro(tcx, src, mir, w)?; for block in mir.all_basic_blocks() { write_basic_block(tcx, block, mir, w, &annotations)?; From 07a6d6d2d5f9e5227c5c5de6adf4ac9b4fb6abdf Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 16:13:44 +0200 Subject: [PATCH 008/179] `rustc_mir::pretty` refactoring: break `fn write_fn_intro` into two routines. (The crucial thing these changes are working toward (but are not yet in this commit) is a way to pretty-print MIR without having the `NodeId` for that MIR in hand.) --- src/librustc_mir/pretty.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index f11d0c84ec29..a6bbd55ffa7a 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -276,6 +276,14 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir, w: &mut Write) -> io::Result<()> { + write_mir_sig(tcx, src, mir, w)?; + writeln!(w, " {{")?; + write_mir_decls(tcx, mir, w) +} + +fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) + -> io::Result<()> +{ match src { MirSource::Fn(_) => write!(w, "fn")?, MirSource::Const(_) => write!(w, "const")?, @@ -301,16 +309,18 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // fn return type. match mir.return_ty { - ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?, - ty::FnOutput::FnDiverging => write!(w, "!")?, + ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty), + ty::FnOutput::FnDiverging => write!(w, "!"), } } else { assert!(mir.arg_decls.is_empty()); - write!(w, ": {} =", mir.return_ty.unwrap())?; + write!(w, ": {} =", mir.return_ty.unwrap()) } +} - writeln!(w, " {{")?; - +fn write_mir_decls(tcx: TyCtxt, mir: &Mir, w: &mut Write) + -> io::Result<()> +{ // User variable types (including the user's name in a comment). for (i, var) in mir.var_decls.iter().enumerate() { let mut_str = if var.mutability == Mutability::Mut { From a5272f2446db7f1cd4003b64b422b01323473249 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 16:22:27 +0200 Subject: [PATCH 009/179] Expose pretty print routines that accept just `mir` (no need for a `NodeId`). --- src/librustc_mir/pretty.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index a6bbd55ffa7a..33f1df17bcba 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -269,6 +269,29 @@ fn write_scope_tree(tcx: TyCtxt, Ok(()) } +pub fn write_mir_named(tcx: &ty::TyCtxt, name: &str, mir: &Mir, w: &mut Write, auxiliary: Option<&ScopeAuxiliaryVec>) +-> io::Result<()> { + + let annotations = scope_entry_exit_annotations(auxiliary); + write_mir_intro_named(tcx, name, mir, w)?; + for block in mir.all_basic_blocks() { + write_basic_block(tcx, block, mir, w, &annotations)?; + } + writeln!(w, "}}") +} + +/// Write out a human-readable textual representation of the MIR's +/// `fn` type and the types of its local variables (both user-defined +/// bindings and compiler temporaries). Assumes the function +/// represented by `mir` is named `name`. Note: Generated output +/// introduces an open curly that needs to be closed. +pub fn write_mir_intro_named(tcx: &ty::TyCtxt, name: &str, mir: &Mir, w: &mut Write) +-> io::Result<()> { + write_mir_fn_sig(tcx, name, mir, w)?; + writeln!(w, " {{")?; + write_mir_fn_decls(tcx, mir, w) +} + /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, From 50bb001e8662258aaa14240dd429cabcbfb8c41d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 17:27:17 +0200 Subject: [PATCH 010/179] One-line doc clarification for representation of unit type `()`. --- src/librustc_mir/pretty.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 33f1df17bcba..a6bbd55ffa7a 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -269,29 +269,6 @@ fn write_scope_tree(tcx: TyCtxt, Ok(()) } -pub fn write_mir_named(tcx: &ty::TyCtxt, name: &str, mir: &Mir, w: &mut Write, auxiliary: Option<&ScopeAuxiliaryVec>) --> io::Result<()> { - - let annotations = scope_entry_exit_annotations(auxiliary); - write_mir_intro_named(tcx, name, mir, w)?; - for block in mir.all_basic_blocks() { - write_basic_block(tcx, block, mir, w, &annotations)?; - } - writeln!(w, "}}") -} - -/// Write out a human-readable textual representation of the MIR's -/// `fn` type and the types of its local variables (both user-defined -/// bindings and compiler temporaries). Assumes the function -/// represented by `mir` is named `name`. Note: Generated output -/// introduces an open curly that needs to be closed. -pub fn write_mir_intro_named(tcx: &ty::TyCtxt, name: &str, mir: &Mir, w: &mut Write) --> io::Result<()> { - write_mir_fn_sig(tcx, name, mir, w)?; - writeln!(w, " {{")?; - write_mir_fn_decls(tcx, mir, w) -} - /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, From 02a89907a8907e4ddd1d795ad9a106850910b30e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 18:00:33 +0200 Subject: [PATCH 011/179] Add helper method for getting the dataflow results at exit from a basic block. --- src/librustc_borrowck/borrowck/mir/dataflow.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow.rs b/src/librustc_borrowck/borrowck/mir/dataflow.rs index d6dd176e3ba2..f0fb0f1515d3 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow.rs @@ -303,6 +303,14 @@ impl AllSets { pub fn on_entry_set_for(&self, block_idx: usize) -> &[usize] { self.lookup_set_for(&self.on_entry_sets, block_idx) } + pub fn on_exit_set_for(&self, block_idx: usize) -> Vec { + let mut set: Vec<_> = self.on_entry_set_for(block_idx).iter() + .map(|x|*x) + .collect(); + bitwise(&mut set[..], self.gen_set_for(block_idx), &Union); + bitwise(&mut set[..], self.kill_set_for(block_idx), &Subtract); + return set; + } } impl DataflowState { From 228d19ac23f085ab341450ccc6b7c03ea46a16e4 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 18:05:28 +0200 Subject: [PATCH 012/179] Remove `&self` parameter from `DataflowOperator::initial_value`. --- src/librustc_borrowck/borrowck/mir/dataflow.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow.rs b/src/librustc_borrowck/borrowck/mir/dataflow.rs index f0fb0f1515d3..fcdb0c4bf540 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow.rs @@ -159,7 +159,7 @@ impl<'c, 'b: 'c, 'a: 'b, 'tcx: 'a, OnReturn> PropagationContext<'c, 'b, 'a, 'tcx where OnReturn: Fn(&MoveData, &mut [usize], &repr::Lvalue) { fn reset(&mut self, bits: &mut [usize]) { - let e = if self.mbcx.flow_state.operator.initial_value() {usize::MAX} else {0}; + let e = if MoveData::initial_value() {usize::MAX} else {0}; for b in bits { *b = e; } @@ -361,7 +361,7 @@ pub trait BitwiseOperator { /// Parameterization for the precise form of data flow that is used. pub trait DataflowOperator : BitwiseOperator { /// Specifies the initial value for each bit in the `on_entry` set - fn initial_value(&self) -> bool; + fn initial_value() -> bool; } pub trait BitDenotation: DataflowOperator { @@ -382,7 +382,7 @@ impl DataflowState { let num_blocks = mir.basic_blocks.len(); let num_words = num_blocks * words_per_block; - let entry = if denotation.initial_value() { usize::MAX } else {0}; + let entry = if D::initial_value() { usize::MAX } else {0}; let zeroes = Bits::new(0, num_words); let on_entry = Bits::new(entry, num_words); @@ -482,7 +482,7 @@ impl<'tcx> BitwiseOperator for MoveData<'tcx> { impl<'tcx> DataflowOperator for MoveData<'tcx> { #[inline] - fn initial_value(&self) -> bool { + fn initial_value() -> bool { false // no loans in scope by default } } From 06a6b04cadb7fe78cc138e14634d2ef8f1c44894 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 28 Apr 2016 18:51:33 +0200 Subject: [PATCH 013/179] Unit struct defns for 3 dataflow analyses for `borrowck::mir::dataflow`. --- .../borrowck/mir/dataflow.rs | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow.rs b/src/librustc_borrowck/borrowck/mir/dataflow.rs index fcdb0c4bf540..5a508ba9e961 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow.rs @@ -14,6 +14,7 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir}; use std::io; +use std::marker::PhantomData; use std::mem; use std::usize; @@ -465,6 +466,122 @@ impl DataflowState { } } +// Dataflow analyses are built upon some interpretation of the +// bitvectors attached to each basic block, represented via a +// zero-sized structure. +// +// Note on PhantomData: Each interpretation will need to instantiate +// the `Bit` and `Ctxt` associated types, and in this case, those +// associated types need an associated lifetime `'tcx`. The +// interpretive structures are zero-sized, so they all need to carry a +// `PhantomData` representing how the structures relate to the `'tcx` +// lifetime. +// +// But, since all of the uses of `'tcx` are solely via instances of +// `Ctxt` that are passed into the `BitDenotation` methods, we can +// consistently use a `PhantomData` that is just a function over a +// `&Ctxt` (== `&MoveData<'tcx>). + +/// `MaybeInitializedLvals` tracks all l-values that might be +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-init: +/// // {} +/// let a = S; let b = S; let c; let d; // {a, b} +/// +/// if pred { +/// drop(a); // { b} +/// b = S; // { b} +/// +/// } else { +/// drop(b); // {a} +/// d = S; // {a, d} +/// +/// } // {a, b, d} +/// +/// c = S; // {a, b, c, d} +/// } +/// ``` +/// +/// To determine whether an l-value *must* be initialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeUninitializedLvals` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeUninitializedLvals` yields the set of +/// l-values that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct MaybeInitializedLvals<'tcx> { + // See "Note on PhantomData" above. + phantom: PhantomData Fn(&'a MoveData<'tcx>)>, +} + +/// `MaybeUninitializedLvals` tracks all l-values that might be +/// uninitialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-uninit: +/// // {a, b, c, d} +/// let a = S; let b = S; let c; let d; // { c, d} +/// +/// if pred { +/// drop(a); // {a, c, d} +/// b = S; // {a, c, d} +/// +/// } else { +/// drop(b); // { b, c, d} +/// d = S; // { b, c } +/// +/// } // {a, b, c, d} +/// +/// c = S; // {a, b, d} +/// } +/// ``` +/// +/// To determine whether an l-value *must* be uninitialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeInitializedLvals` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeInitializedLvals` yields the set of +/// l-values that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct MaybeUninitializedLvals<'tcx> { + // See "Note on PhantomData" above. + phantom: PhantomData Fn(&'a MoveData<'tcx>)>, +} + +/// `MovingOutStatements` tracks the statements that perform moves out +/// of particular l-values. More precisely, it tracks whether the +/// *effect* of such moves (namely, the uninitialization of the +/// l-value in question) can reach some point in the control-flow of +/// the function, or if that effect is "killed" by some intervening +/// operation reinitializing that l-value. +/// +/// The resulting dataflow is a more enriched version of +/// `MaybeUninitializedLvals`. Both structures on their own only tell +/// you if an l-value *might* be uninitialized at a given point in the +/// control flow. But `MovingOutStatements` also includes the added +/// data of *which* particular statement causing the deinitialization +/// that the borrow checker's error meessage may need to report. +#[derive(Debug, Default)] +pub struct MovingOutStatements<'tcx> { + // See "Note on PhantomData" above. + phantom: PhantomData Fn(&'a MoveData<'tcx>)>, +} impl<'a, 'tcx> DataflowState> { pub fn new_move_analysis(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { From cda9c565c256bbacdd0b066eff21057d16286681 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 2 May 2016 13:28:13 +0200 Subject: [PATCH 014/179] `borrowck::mir::gather_moves`: create MovePaths for lvalues even if unreferenced. includes misc bug fixes and removal of useless code. --- .../borrowck/mir/gather_moves.rs | 106 ++++++++++++------ 1 file changed, 74 insertions(+), 32 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index bf3d671bdb5a..64a7dddc8aba 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -9,7 +9,7 @@ // except according to those terms. -use rustc::ty::TyCtxt; +use rustc::ty::{FnOutput, TyCtxt}; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; @@ -419,6 +419,11 @@ impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> { self.rev_lookup.lookup_proj(proj, base_index) } + fn create_move_path(&mut self, lval: &Lvalue<'tcx>) { + // Create MovePath for `lval`, discarding returned index. + self.move_path_for(lval); + } + fn move_path_for(&mut self, lval: &Lvalue<'tcx>) -> MovePathIndex { let lookup: Lookup = self.lookup(lval); @@ -491,7 +496,7 @@ impl<'a, 'tcx> MoveData<'tcx> { #[derive(Debug)] enum StmtKind { Use, Repeat, Cast, BinaryOp, UnaryOp, Box, - Aggregate, Drop, CallFn, CallArg, Return, + Aggregate, Drop, CallFn, CallArg, Return, If, } fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveData<'tcx> { @@ -511,6 +516,27 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD rev_lookup: MovePathLookup::new(), }; + // Before we analyze the program text, we create the MovePath's + // for all of the vars, args, and temps. (This enforces a basic + // property that even if the MIR body doesn't contain any + // references to a var/arg/temp, it will still be a valid + // operation to lookup the MovePath associated with it.) + assert!(mir.var_decls.len() <= ::std::u32::MAX as usize); + assert!(mir.arg_decls.len() <= ::std::u32::MAX as usize); + assert!(mir.temp_decls.len() <= ::std::u32::MAX as usize); + for var_idx in 0..mir.var_decls.len() { + let path_idx = builder.move_path_for(&Lvalue::Var(var_idx as u32)); + path_map.fill_to(path_idx.idx()); + } + for arg_idx in 0..mir.arg_decls.len() { + let path_idx = builder.move_path_for(&Lvalue::Arg(arg_idx as u32)); + path_map.fill_to(path_idx.idx()); + } + for temp_idx in 0..mir.temp_decls.len() { + let path_idx = builder.move_path_for(&Lvalue::Temp(temp_idx as u32)); + path_map.fill_to(path_idx.idx()); + } + for bb in bbs { let loc_map_bb = &mut loc_map[bb.index()]; let bb_data = mir.basic_block_data(bb); @@ -532,8 +558,12 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD let source = Location { block: bb, index: i }; match stmt.kind { StatementKind::Assign(ref lval, ref rval) => { - // ensure MovePath created for `lval`. - bb_ctxt.builder.move_path_for(lval); + bb_ctxt.builder.create_move_path(lval); + + // Ensure that the path_map contains entries even + // if the lvalue is assigned and never read. + let assigned_path = bb_ctxt.builder.move_path_for(lval); + bb_ctxt.path_map.fill_to(assigned_path.idx()); match *rval { Rvalue::Use(ref operand) => { @@ -569,7 +599,26 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD Rvalue::InlineAsm { .. } => {} Rvalue::Slice {..} => { - bug!("cannot move out of slice"); + // A slice pattern `x..` binds `x` to a + // reference; thus no move occurs. + // + // FIXME: I recall arielb1 questioning + // whether this is even a legal thing to + // have as an R-value. The particular + // example where I am seeing this arise is + // `TargetDataLayout::parse(&Session)` in + // `rustc::ty::layout`. + debug!("encountered Rvalue::Slice as RHS of Assign, source: {:?} \n{}", + source, { + let mut out = Vec::new(); + { + use std::io::Write; + use rustc_mir::pretty::write_mir_named; + let mut w: &mut Write = &mut out; + write_mir_named(tcx, "boo_attempt_move_out_of_slice", mir, &mut w, None).unwrap(); + } + String::from_utf8(out).unwrap() + }); } } } @@ -582,14 +631,19 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Return => { let source = Location { block: bb, index: bb_data.statements.len() }; - let lval = &Lvalue::ReturnPointer.deref(); - bb_ctxt.on_move_out_lval(SK::Return, lval, source); + if let FnOutput::FnConverging(_) = bb_ctxt.builder.mir.return_ty { + debug!("gather_moves Return on_move_out_lval return {:?}", source); + bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); + } else { + debug!("gather_moves Return on_move_out_lval assuming unreachable return {:?}", source); + } } TerminatorKind::If { ref cond, targets: _ } => { - // The `cond` is always of (copyable) type `bool`, - // so there will never be anything to move. - let _ = cond; + let source = Location { block: bb, + index: bb_data.statements.len() }; + debug!("gather_moves If on_operand {:?} {:?}", cond, source); + bb_ctxt.on_operand(SK::If, cond, source); } TerminatorKind::SwitchInt { switch_ty: _, values: _, targets: _, ref discr } | @@ -604,6 +658,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Drop { value: ref lval, target: _, unwind: _ } => { let source = Location { block: bb, index: bb_data.statements.len() }; + debug!("gather_moves Drop on_move_out_lval {:?} {:?}", lval, source); bb_ctxt.on_move_out_lval(SK::Drop, lval, source); } @@ -612,12 +667,18 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD index: bb_data.statements.len() }; bb_ctxt.on_operand(SK::CallFn, func, source); for arg in args { + debug!("gather_moves Call on_operand {:?} {:?}", arg, source); bb_ctxt.on_operand(SK::CallArg, arg, source); } if let Some((ref destination, _bb)) = *destination { - // Create MovePath for `destination`, then - // discard returned index. - bb_ctxt.builder.move_path_for(destination); + debug!("gather_moves Call create_move_path {:?} {:?}", destination, source); + + // Ensure that the path_map contains entries even + // if the lvalue is assigned and never read. + let assigned_path = bb_ctxt.builder.move_path_for(destination); + bb_ctxt.path_map.fill_to(assigned_path.idx()); + + bb_ctxt.builder.create_move_path(destination); } } } @@ -635,7 +696,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD // // well you know, lets actually try just asserting that the path map *is* complete. assert_eq!(path_map.len(), builder.pre_move_paths.len()); - path_map.fill_to(builder.pre_move_paths.len() - 1); let pre_move_paths = builder.pre_move_paths; let move_paths: Vec<_> = pre_move_paths.into_iter() @@ -680,24 +740,6 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> { lval: &Lvalue<'tcx>, source: Location) { let tcx = self.tcx; - let lval_ty = self.builder.mir.lvalue_ty(tcx, lval); - - // FIXME: does lvalue_ty ever return TyError, or is it - // guaranteed to always return non-Infer/non-Error values? - - // This code is just trying to avoid creating a MoveOut - // entry for values that do not need move semantics. - // - // type_contents is imprecise (may claim needs drop for - // types that in fact have no destructor). But that is - // still usable for our purposes here. - let consumed = lval_ty.to_ty(tcx).type_contents(tcx).needs_drop(tcx); - - if !consumed { - debug!("ctxt: {:?} no consume of lval: {:?} of type {:?}", - stmt_kind, lval, lval_ty); - return; - } let i = source.index; let index = MoveOutIndex::new(self.moves.len()); From 5d9c0bbe50b533742346381b834a14cb0893b2ce Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 2 May 2016 15:50:27 +0200 Subject: [PATCH 015/179] Revised mir-dataflow. Incorporates many fixes contributed by arielb1. ---- revise borrowck::mir::dataflow code to allow varying domain for bitvectors. This particular code implements the `BitDenotation` trait for three analyses: * `MovingOutStatements`, which, like `borrowck::move_data`, maps each bit-index to a move instruction, and a 1 means "the effect of this move reaches this point" (and the assigned l-value, if a scoped declaration, is still in scope). * `MaybeInitializedLvals`, which maps each bit-index to an l-value. A 1 means "there exists a control flow path to this point that initializes the associated l-value." * `MaybeUninitializedLvals`, which maps each bit-index to an l-value A 1 means "there exists a control flow path to this point that de-initializes the associated l-value." ---- Revised `graphviz` dataflow-rendering support in `borrowck::mir`. One big difference is that this code is now parameterized over the `BitDenotation`, so that it can be used to render dataflow results independent of how the dataflow bitvectors are interpreted; see where reference to `MoveOut` is replaced by the type parameter `D`. ---- Factor out routine to query subattributes in `#[rustc_mir(..)]`. (Later commits build upon this for some unit testing and instrumentation.) ---- thread through a tcx so that I can query types of lvalues as part of analysis. ---- Revised `BitDenotation::Ctxt`, allowing variation beyond `MoveData`. The main motivation is to ease threading through a `TyCtxt`. (In hindsight it might have been better to instead attach the `TyCtxt` to each of the different dataflow implementations, but that would require e.g. switching away from having a `Default` impl, so I am leaving that experiment for another time.) --- src/librustc/mir/repr.rs | 3 +- src/librustc/mir/transform.rs | 2 +- .../borrowck/mir/dataflow.rs | 629 ---------- .../borrowck/mir/{ => dataflow}/graphviz.rs | 140 ++- .../borrowck/mir/dataflow/mod.rs | 1024 +++++++++++++++++ .../borrowck/mir/gather_moves.rs | 57 +- src/librustc_borrowck/borrowck/mir/mod.rs | 233 +++- 7 files changed, 1368 insertions(+), 720 deletions(-) delete mode 100644 src/librustc_borrowck/borrowck/mir/dataflow.rs rename src/librustc_borrowck/borrowck/mir/{ => dataflow}/graphviz.rs (58%) create mode 100644 src/librustc_borrowck/borrowck/mir/dataflow/mod.rs diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 458cb28144ad..f9a671435ffd 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -226,7 +226,8 @@ pub struct UpvarDecl { /// list of the `Mir`. /// /// (We use a `u32` internally just to save memory.) -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, + RustcEncodable, RustcDecodable)] pub struct BasicBlock(u32); impl BasicBlock { diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 79c44b2b851c..828a48532a2f 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -18,7 +18,7 @@ use ty::TyCtxt; use syntax::ast::NodeId; /// Where a specific Mir comes from. -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub enum MirSource { /// Functions and methods. Fn(NodeId), diff --git a/src/librustc_borrowck/borrowck/mir/dataflow.rs b/src/librustc_borrowck/borrowck/mir/dataflow.rs deleted file mode 100644 index 5a508ba9e961..000000000000 --- a/src/librustc_borrowck/borrowck/mir/dataflow.rs +++ /dev/null @@ -1,629 +0,0 @@ -// Copyright 2012-2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use syntax::attr::AttrMetaMethods; - -use rustc::ty::TyCtxt; -use rustc::mir::repr::{self, Mir}; - -use std::io; -use std::marker::PhantomData; -use std::mem; -use std::usize; - -use super::MirBorrowckCtxt; -use super::gather_moves::{Location, MoveData, MovePathData, MovePathIndex, MoveOutIndex, PathMap}; -use super::graphviz; -use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. - -pub trait Dataflow { - fn dataflow(&mut self); -} - -impl<'b, 'a: 'b, 'tcx: 'a> Dataflow for MirBorrowckCtxt<'b, 'a, 'tcx> { - fn dataflow(&mut self) { - self.build_gen_and_kill_sets(); - self.pre_dataflow_instrumentation().unwrap(); - self.propagate(); - self.post_dataflow_instrumentation().unwrap(); - } -} - -struct PropagationContext<'c, 'b: 'c, 'a: 'b, 'tcx: 'a, OnReturn> - where OnReturn: Fn(&MoveData, &mut [usize], &repr::Lvalue) -{ - mbcx: &'c mut MirBorrowckCtxt<'b, 'a, 'tcx>, - changed: bool, - on_return: OnReturn -} - -impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { - fn propagate(&mut self) { - let mut temp = vec![0; self.flow_state.sets.words_per_block]; - let mut propcx = PropagationContext { - mbcx: &mut *self, - changed: true, - on_return: |move_data, in_out, dest_lval| { - let move_path_index = move_data.rev_lookup.find(dest_lval); - on_all_children_bits(in_out, - &move_data.path_map, - &move_data.move_paths, - move_path_index, - &|in_out, mpi| { - in_out.clear_bit(mpi.idx()); - }); - }, - }; - while propcx.changed { - propcx.changed = false; - propcx.reset(&mut temp); - propcx.walk_cfg(&mut temp); - } - } - - fn build_gen_and_kill_sets(&mut self) { - // First we need to build the gen- and kill-sets. The - // gather_moves information provides a high-level mapping from - // mir-locations to the MoveOuts (and those correspond - // directly to gen-sets here). But we still need to figure out - // the kill-sets. - - let move_data = &self.flow_state.operator; - let move_paths = &move_data.move_paths; - let loc_map = &move_data.loc_map; - let path_map = &move_data.path_map; - let rev_lookup = &move_data.rev_lookup; - - for bb in self.mir.all_basic_blocks() { - let &repr::BasicBlockData { ref statements, - ref terminator, - is_cleanup: _ } = - self.mir.basic_block_data(bb); - - let mut sets = self.flow_state.sets.for_block(bb.index()); - for (j, stmt) in statements.iter().enumerate() { - let loc = Location { block: bb, index: j }; - debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}", - stmt, loc, &loc_map[loc]); - for move_index in &loc_map[loc] { - // Every path deinitialized by a *particular move* - // has corresponding bit, "gen'ed" (i.e. set) - // here, in dataflow vector - zero_to_one(&mut sets.gen_set, *move_index); - } - match stmt.kind { - repr::StatementKind::Assign(ref lvalue, _) => { - // assigning into this `lvalue` kills all - // MoveOuts from it, and *also* all MoveOuts - // for children and associated fragment sets. - let move_path_index = rev_lookup.find(lvalue); - - on_all_children_bits(sets.kill_set, - path_map, - move_paths, - move_path_index, - &|kill_set, mpi| { - kill_set.set_bit(mpi.idx()); - }); - } - } - } - - let loc = Location { block: bb, index: statements.len() }; - debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}", - terminator, loc, &loc_map[loc]); - for move_index in &loc_map[loc] { - zero_to_one(&mut sets.gen_set, *move_index); - } - } - - fn zero_to_one(gen_set: &mut [usize], move_index: MoveOutIndex) { - let retval = gen_set.set_bit(move_index.idx()); - assert!(retval); - } - } -} - -fn on_all_children_bits(set: &mut [usize], - path_map: &PathMap, - move_paths: &MovePathData, - move_path_index: MovePathIndex, - each_child: &Each) - where Each: Fn(&mut [usize], MoveOutIndex) -{ - // 1. invoke `each_child` callback for all moves that directly - // influence path for `move_path_index` - for move_index in &path_map[move_path_index] { - each_child(set, *move_index); - } - - // 2. for each child of the path (that is named in this - // function), recur. - // - // (Unnamed children are irrelevant to dataflow; by - // definition they have no associated moves.) - let mut next_child_index = move_paths[move_path_index].first_child; - while let Some(child_index) = next_child_index { - on_all_children_bits(set, path_map, move_paths, child_index, each_child); - next_child_index = move_paths[child_index].next_sibling; - } -} - -impl<'c, 'b: 'c, 'a: 'b, 'tcx: 'a, OnReturn> PropagationContext<'c, 'b, 'a, 'tcx, OnReturn> - where OnReturn: Fn(&MoveData, &mut [usize], &repr::Lvalue) -{ - fn reset(&mut self, bits: &mut [usize]) { - let e = if MoveData::initial_value() {usize::MAX} else {0}; - for b in bits { - *b = e; - } - } - - fn walk_cfg(&mut self, in_out: &mut [usize]) { - let &mut MirBorrowckCtxt { ref mir, ref mut flow_state, .. } = self.mbcx; - for (idx, bb) in mir.basic_blocks.iter().enumerate() { - { - let sets = flow_state.sets.for_block(idx); - debug_assert!(in_out.len() == sets.on_entry.len()); - in_out.clone_from_slice(sets.on_entry); - bitwise(in_out, sets.gen_set, &Union); - bitwise(in_out, sets.kill_set, &Subtract); - } - flow_state.propagate_bits_into_graph_successors_of(in_out, - &mut self.changed, - bb, - &self.on_return); - } - } -} - -impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { - fn pre_dataflow_instrumentation(&self) -> io::Result<()> { - self.if_attr_meta_name_found( - "borrowck_graphviz_preflow", - |this, path: &str| { - graphviz::print_borrowck_graph_to(this, "preflow", path) - }) - } - - fn post_dataflow_instrumentation(&self) -> io::Result<()> { - self.if_attr_meta_name_found( - "borrowck_graphviz_postflow", - |this, path: &str| { - graphviz::print_borrowck_graph_to(this, "postflow", path) - }) - } - - fn if_attr_meta_name_found(&self, - name: &str, - callback: F) -> io::Result<()> - where F: for <'aa, 'bb> FnOnce(&'aa Self, &'bb str) -> io::Result<()> - { - for attr in self.attributes { - if attr.check_name("rustc_mir") { - let items = attr.meta_item_list(); - for item in items.iter().flat_map(|l| l.iter()) { - if item.check_name(name) { - if let Some(s) = item.value_str() { - return callback(self, &s); - } else { - self.bcx.tcx.sess.span_err( - item.span, - &format!("{} attribute requires a path", item.name())); - } - } - } - } - } - - Ok(()) - } -} - -/// Maps each block to a set of bits -#[derive(Clone, Debug)] -struct Bits { - bits: Vec, -} - -impl Bits { - fn new(init_word: usize, num_words: usize) -> Self { - Bits { bits: vec![init_word; num_words] } - } -} - -pub struct DataflowState -{ - /// All the sets for the analysis. (Factored into its - /// own structure so that we can borrow it mutably - /// on its own separate from other fields.) - pub sets: AllSets, - - /// operator used to initialize, combine, and interpret bits. - operator: O, -} - -pub struct AllSets { - /// Analysis bitwidth for each block. - bits_per_block: usize, - - /// Number of words associated with each block entry - /// equal to bits_per_block / usize::BITS, rounded up. - words_per_block: usize, - - /// For each block, bits generated by executing the statements in - /// the block. (For comparison, the Terminator for each block is - /// handled in a flow-specific manner during propagation.) - gen_sets: Bits, - - /// For each block, bits killed by executing the statements in the - /// block. (For comparison, the Terminator for each block is - /// handled in a flow-specific manner during propagation.) - kill_sets: Bits, - - /// For each block, bits valid on entry to the block. - on_entry_sets: Bits, -} - -pub struct BlockSets<'a> { - on_entry: &'a mut [usize], - gen_set: &'a mut [usize], - kill_set: &'a mut [usize], -} - -impl AllSets { - pub fn bits_per_block(&self) -> usize { self.bits_per_block } - pub fn bytes_per_block(&self) -> usize { (self.bits_per_block + 7) / 8 } - pub fn for_block(&mut self, block_idx: usize) -> BlockSets { - let offset = self.words_per_block * block_idx; - let range = offset..(offset + self.words_per_block); - BlockSets { - on_entry: &mut self.on_entry_sets.bits[range.clone()], - gen_set: &mut self.gen_sets.bits[range.clone()], - kill_set: &mut self.kill_sets.bits[range], - } - } - - fn lookup_set_for<'a>(&self, sets: &'a Bits, block_idx: usize) -> &'a [usize] { - let offset = self.words_per_block * block_idx; - &sets.bits[offset..(offset + self.words_per_block)] - } - pub fn gen_set_for(&self, block_idx: usize) -> &[usize] { - self.lookup_set_for(&self.gen_sets, block_idx) - } - pub fn kill_set_for(&self, block_idx: usize) -> &[usize] { - self.lookup_set_for(&self.kill_sets, block_idx) - } - pub fn on_entry_set_for(&self, block_idx: usize) -> &[usize] { - self.lookup_set_for(&self.on_entry_sets, block_idx) - } - pub fn on_exit_set_for(&self, block_idx: usize) -> Vec { - let mut set: Vec<_> = self.on_entry_set_for(block_idx).iter() - .map(|x|*x) - .collect(); - bitwise(&mut set[..], self.gen_set_for(block_idx), &Union); - bitwise(&mut set[..], self.kill_set_for(block_idx), &Subtract); - return set; - } -} - -impl DataflowState { - fn each_bit(&self, words: &[usize], mut f: F) - where F: FnMut(usize) { - //! Helper for iterating over the bits in a bitvector. - - for (word_index, &word) in words.iter().enumerate() { - if word != 0 { - let usize_bits: usize = mem::size_of::(); - let base_index = word_index * usize_bits; - for offset in 0..usize_bits { - let bit = 1 << offset; - if (word & bit) != 0 { - // NB: we round up the total number of bits - // that we store in any given bit set so that - // it is an even multiple of usize::BITS. This - // means that there may be some stray bits at - // the end that do not correspond to any - // actual value; that's why we first check - // that we are in range of bits_per_block. - let bit_index = base_index + offset as usize; - if bit_index >= self.sets.bits_per_block() { - return; - } else { - f(bit_index); - } - } - } - } - } - } - - pub fn interpret_set(&self, words: &[usize]) -> Vec<&O::Bit> { - let mut v = Vec::new(); - self.each_bit(words, |i| { - v.push(self.operator.interpret(i)); - }); - v - } -} - -pub trait BitwiseOperator { - /// Joins two predecessor bits together, typically either `|` or `&` - fn join(&self, pred1: usize, pred2: usize) -> usize; -} - -/// Parameterization for the precise form of data flow that is used. -pub trait DataflowOperator : BitwiseOperator { - /// Specifies the initial value for each bit in the `on_entry` set - fn initial_value() -> bool; -} - -pub trait BitDenotation: DataflowOperator { - /// Specifies what is represented by each bit in the dataflow bitvector. - type Bit; - /// Size of each bivector allocated for each block in the analysis. - fn bits_per_block(&self) -> usize; - /// Provides the meaning of each entry in the dataflow bitvector. - /// (Mostly intended for use for better debug instrumentation.) - fn interpret(&self, idx: usize) -> &Self::Bit; -} - -impl DataflowState { - pub fn new(mir: &Mir, denotation: D) -> Self { - let bits_per_block = denotation.bits_per_block(); - let usize_bits = mem::size_of::() * 8; - let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits; - let num_blocks = mir.basic_blocks.len(); - let num_words = num_blocks * words_per_block; - - let entry = if D::initial_value() { usize::MAX } else {0}; - - let zeroes = Bits::new(0, num_words); - let on_entry = Bits::new(entry, num_words); - - DataflowState { - sets: AllSets { - bits_per_block: bits_per_block, - words_per_block: words_per_block, - gen_sets: zeroes.clone(), - kill_sets: zeroes, - on_entry_sets: on_entry, - }, - operator: denotation, - } - } -} - -impl DataflowState { - /// Propagates the bits of `in_out` into all the successors of `bb`, - /// using bitwise operator denoted by `self.operator`. - /// - /// For most blocks, this is entirely uniform. However, for blocks - /// that end with a call terminator, the effect of the call on the - /// dataflow state may depend on whether the call returned - /// successfully or unwound. To reflect this, the `on_return` - /// callback mutates `in_out` when propagating `in_out` via a call - /// terminator; such mutation is performed *last*, to ensure its - /// side-effects do not leak elsewhere (e.g. into unwind target). - fn propagate_bits_into_graph_successors_of( - &mut self, - in_out: &mut [usize], - changed: &mut bool, - bb: &repr::BasicBlockData, - on_return: OnReturn) where OnReturn: Fn(&D, &mut [usize], &repr::Lvalue) - { - match bb.terminator().kind { - repr::TerminatorKind::Return | - repr::TerminatorKind::Resume => {} - repr::TerminatorKind::Goto { ref target } | - repr::TerminatorKind::Drop { ref target, value: _, unwind: None } => { - self.propagate_bits_into_entry_set_for(in_out, changed, target); - } - repr::TerminatorKind::Drop { ref target, value: _, unwind: Some(ref unwind) } => { - self.propagate_bits_into_entry_set_for(in_out, changed, target); - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); - } - repr::TerminatorKind::If { ref targets, .. } => { - self.propagate_bits_into_entry_set_for(in_out, changed, &targets.0); - self.propagate_bits_into_entry_set_for(in_out, changed, &targets.1); - } - repr::TerminatorKind::Switch { ref targets, .. } | - repr::TerminatorKind::SwitchInt { ref targets, .. } => { - for target in targets { - self.propagate_bits_into_entry_set_for(in_out, changed, target); - } - } - repr::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { - if let Some(ref unwind) = *cleanup { - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); - } - if let Some((ref dest_lval, ref dest_bb)) = *destination { - // N.B.: This must be done *last*, after all other - // propagation, as documented in comment above. - on_return(&self.operator, in_out, dest_lval); - self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb); - } - } - } - } - - fn propagate_bits_into_entry_set_for(&mut self, - in_out: &[usize], - changed: &mut bool, - bb: &repr::BasicBlock) { - let entry_set = self.sets.for_block(bb.index()).on_entry; - let set_changed = bitwise(entry_set, in_out, &self.operator); - if set_changed { - *changed = true; - } - } -} - -// Dataflow analyses are built upon some interpretation of the -// bitvectors attached to each basic block, represented via a -// zero-sized structure. -// -// Note on PhantomData: Each interpretation will need to instantiate -// the `Bit` and `Ctxt` associated types, and in this case, those -// associated types need an associated lifetime `'tcx`. The -// interpretive structures are zero-sized, so they all need to carry a -// `PhantomData` representing how the structures relate to the `'tcx` -// lifetime. -// -// But, since all of the uses of `'tcx` are solely via instances of -// `Ctxt` that are passed into the `BitDenotation` methods, we can -// consistently use a `PhantomData` that is just a function over a -// `&Ctxt` (== `&MoveData<'tcx>). - -/// `MaybeInitializedLvals` tracks all l-values that might be -/// initialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-init: -/// // {} -/// let a = S; let b = S; let c; let d; // {a, b} -/// -/// if pred { -/// drop(a); // { b} -/// b = S; // { b} -/// -/// } else { -/// drop(b); // {a} -/// d = S; // {a, d} -/// -/// } // {a, b, d} -/// -/// c = S; // {a, b, c, d} -/// } -/// ``` -/// -/// To determine whether an l-value *must* be initialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeUninitializedLvals` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeUninitializedLvals` yields the set of -/// l-values that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] -pub struct MaybeInitializedLvals<'tcx> { - // See "Note on PhantomData" above. - phantom: PhantomData Fn(&'a MoveData<'tcx>)>, -} - -/// `MaybeUninitializedLvals` tracks all l-values that might be -/// uninitialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-uninit: -/// // {a, b, c, d} -/// let a = S; let b = S; let c; let d; // { c, d} -/// -/// if pred { -/// drop(a); // {a, c, d} -/// b = S; // {a, c, d} -/// -/// } else { -/// drop(b); // { b, c, d} -/// d = S; // { b, c } -/// -/// } // {a, b, c, d} -/// -/// c = S; // {a, b, d} -/// } -/// ``` -/// -/// To determine whether an l-value *must* be uninitialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeInitializedLvals` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeInitializedLvals` yields the set of -/// l-values that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] -pub struct MaybeUninitializedLvals<'tcx> { - // See "Note on PhantomData" above. - phantom: PhantomData Fn(&'a MoveData<'tcx>)>, -} - -/// `MovingOutStatements` tracks the statements that perform moves out -/// of particular l-values. More precisely, it tracks whether the -/// *effect* of such moves (namely, the uninitialization of the -/// l-value in question) can reach some point in the control-flow of -/// the function, or if that effect is "killed" by some intervening -/// operation reinitializing that l-value. -/// -/// The resulting dataflow is a more enriched version of -/// `MaybeUninitializedLvals`. Both structures on their own only tell -/// you if an l-value *might* be uninitialized at a given point in the -/// control flow. But `MovingOutStatements` also includes the added -/// data of *which* particular statement causing the deinitialization -/// that the borrow checker's error meessage may need to report. -#[derive(Debug, Default)] -pub struct MovingOutStatements<'tcx> { - // See "Note on PhantomData" above. - phantom: PhantomData Fn(&'a MoveData<'tcx>)>, -} - -impl<'a, 'tcx> DataflowState> { - pub fn new_move_analysis(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - let move_data = MoveData::gather_moves(mir, tcx); - DataflowState::new(mir, move_data) - } -} - -impl<'tcx> BitwiseOperator for MoveData<'tcx> { - #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { - pred1 | pred2 // moves from both preds are in scope - } -} - -impl<'tcx> DataflowOperator for MoveData<'tcx> { - #[inline] - fn initial_value() -> bool { - false // no loans in scope by default - } -} - -#[inline] -fn bitwise(out_vec: &mut [usize], - in_vec: &[usize], - op: &Op) -> bool { - assert_eq!(out_vec.len(), in_vec.len()); - let mut changed = false; - for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) { - let old_val = *out_elt; - let new_val = op.join(old_val, *in_elt); - *out_elt = new_val; - changed |= old_val != new_val; - } - changed -} - -struct Union; -impl BitwiseOperator for Union { - fn join(&self, a: usize, b: usize) -> usize { a | b } -} -struct Subtract; -impl BitwiseOperator for Subtract { - fn join(&self, a: usize, b: usize) -> usize { a & !b } -} diff --git a/src/librustc_borrowck/borrowck/mir/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs similarity index 58% rename from src/librustc_borrowck/borrowck/mir/graphviz.rs rename to src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 460c71dee3d7..bc6ee89fa257 100644 --- a/src/librustc_borrowck/borrowck/mir/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -10,30 +10,58 @@ //! Hook into libgraphviz for rendering dataflow graphs for MIR. +use syntax::ast::NodeId; use rustc::mir::repr::{BasicBlock, Mir}; use dot; use dot::IntoCow; +use std::fmt::Debug; use std::fs::File; use std::io; use std::io::prelude::*; +use std::marker::PhantomData; +use std::path::Path; -use super::MirBorrowckCtxt; +use super::super::MirBorrowckCtxtPreDataflow; use bitslice::bits_to_string; -use super::gather_moves::MoveOut; +use super::{BitDenotation, DataflowState}; +use super::{HasMoveData}; -struct Graph<'c, 'b:'c, 'a:'b, 'tcx:'a> { mbcx: &'c MirBorrowckCtxt<'b, 'a, 'tcx>, - context: &'b str } +pub trait MirWithFlowState<'tcx> { + type BD: BitDenotation; + fn node_id(&self) -> NodeId; + fn mir(&self) -> &Mir<'tcx>; + fn analysis_ctxt(&self) -> &::Ctxt; + fn flow_state(&self) -> &DataflowState; +} + +impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> + where 'a, 'tcx: 'a, BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> +{ + type BD = BD; + fn node_id(&self) -> NodeId { self.node_id } + fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() } + fn analysis_ctxt(&self) -> &BD::Ctxt { &self.flow_state.ctxt } + fn flow_state(&self) -> &DataflowState { &self.flow_state.flow_state } +} -pub fn print_borrowck_graph_to(mbcx: &MirBorrowckCtxt, - context: &str, - path: &str) -> io::Result<()> { - let g = Graph { mbcx: mbcx, context: context }; +struct Graph<'a, 'tcx, MWF:'a> where MWF: MirWithFlowState<'tcx>, +{ + mbcx: &'a MWF, + phantom: PhantomData<&'tcx ()> +} + +pub fn print_borrowck_graph_to<'a, 'tcx, BD>( + mbcx: &MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>, + path: &Path) -> io::Result<()> where BD: BitDenotation, + BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> +{ + let g = Graph { mbcx: mbcx, phantom: PhantomData }; let mut v = Vec::new(); dot::render(&g, &mut v)?; - println!("print_borrowck_graph_to path: {} context: {} node_id: {}", - path, context, mbcx.node_id); + debug!("print_borrowck_graph_to path: {} node_id: {}", + path.display(), mbcx.node_id); File::create(path).and_then(|mut f| f.write_all(&v)) } @@ -47,13 +75,14 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec { (0..succ_len).map(|index| Edge { source: bb, index: index}).collect() } -impl<'c, 'b:'c, 'a:'b, 'tcx:'a> dot::Labeller<'c> for Graph<'c,'b,'a,'tcx> { +impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> + where MWF: MirWithFlowState<'tcx>, ::Bit: Debug +{ type Node = Node; type Edge = Edge; fn graph_id(&self) -> dot::Id { - dot::Id::new(format!("graph_for_node_{}_{}", - self.mbcx.node_id, - self.context)) + dot::Id::new(format!("graph_for_node_{}", + self.mbcx.node_id())) .unwrap() } @@ -106,10 +135,10 @@ impl<'c, 'b:'c, 'a:'b, 'tcx:'a> dot::Labeller<'c> for Graph<'c,'b,'a,'tcx> { const BG_FLOWCONTENT: &'static str = r#"bgcolor="pink""#; const ALIGN_RIGHT: &'static str = r#"align="right""#; const FACE_MONOSPACE: &'static str = r#"FACE="Courier""#; - fn chunked_present_left(w: &mut W, - interpreted: &[&MoveOut], - chunk_size: usize) - -> io::Result<()> + fn chunked_present_left(w: &mut W, + interpreted: &[&D], + chunk_size: usize) + -> io::Result<()> { // This function may emit a sequence of 's, but it // always finishes with an (unfinished) @@ -137,40 +166,55 @@ impl<'c, 'b:'c, 'a:'b, 'tcx:'a> dot::Labeller<'c> for Graph<'c,'b,'a,'tcx> { Ok(()) } ::rustc_mir::graphviz::write_node_label( - *n, self.mbcx.mir, &mut v, 4, + *n, self.mbcx.mir(), &mut v, 4, |w| { - let flow = &self.mbcx.flow_state; - let entry = flow.interpret_set(flow.sets.on_entry_set_for(i)); - chunked_present_left(w, &entry[..], chunk_size)?; + let ctxt = self.mbcx.analysis_ctxt(); + let flow = self.mbcx.flow_state(); + let entry_interp = flow.interpret_set(ctxt, flow.sets.on_entry_set_for(i)); + chunked_present_left(w, &entry_interp[..], chunk_size)?; + let bits_per_block = flow.sets.bits_per_block(); + let entry = flow.sets.on_entry_set_for(i); + debug!("entry set for i={i} bits_per_block: {bpb} entry: {e:?} interp: {ei:?}", + i=i, e=entry, bpb=bits_per_block, ei=entry_interp); write!(w, "= ENTRY:{entrybits:?}\ ", bg = BG_FLOWCONTENT, face = FACE_MONOSPACE, - entrybits=bits_to_string(flow.sets.on_entry_set_for(i), - flow.sets.bytes_per_block())) + entrybits=bits_to_string(entry, bits_per_block)) }, |w| { - let flow = &self.mbcx.flow_state; - let gen = flow.interpret_set( flow.sets.gen_set_for(i)); - let kill = flow.interpret_set(flow.sets.kill_set_for(i)); - chunked_present_left(w, &gen[..], chunk_size)?; - write!(w, " = GEN:{genbits:?}\ - ", - bg = BG_FLOWCONTENT, - face = FACE_MONOSPACE, - genbits=bits_to_string( flow.sets.gen_set_for(i), - flow.sets.bytes_per_block()))?; - write!(w, "KILL:\ - {killbits:?}", - bg = BG_FLOWCONTENT, - align = ALIGN_RIGHT, - face = FACE_MONOSPACE, - killbits=bits_to_string(flow.sets.kill_set_for(i), - flow.sets.bytes_per_block()))?; + let ctxt = self.mbcx.analysis_ctxt(); + let flow = self.mbcx.flow_state(); + let gen_interp = flow.interpret_set(ctxt, flow.sets.gen_set_for(i)); + let kill_interp = flow.interpret_set(ctxt, flow.sets.kill_set_for(i)); + chunked_present_left(w, &gen_interp[..], chunk_size)?; + let bits_per_block = flow.sets.bits_per_block(); + { + let gen = flow.sets.gen_set_for(i); + debug!("gen set for i={i} bits_per_block: {bpb} gen: {g:?} interp: {gi:?}", + i=i, g=gen, bpb=bits_per_block, gi=gen_interp); + write!(w, " = GEN:{genbits:?}\ + ", + bg = BG_FLOWCONTENT, + face = FACE_MONOSPACE, + genbits=bits_to_string(gen, bits_per_block))?; + } + + { + let kill = flow.sets.kill_set_for(i); + debug!("kill set for i={i} bits_per_block: {bpb} kill: {k:?} interp: {ki:?}", + i=i, k=kill, bpb=bits_per_block, ki=kill_interp); + write!(w, "KILL:\ + {killbits:?}", + bg = BG_FLOWCONTENT, + align = ALIGN_RIGHT, + face = FACE_MONOSPACE, + killbits=bits_to_string(kill, bits_per_block))?; + } // (chunked_present_right) let mut seen_one = false; - for k in kill.chunks(chunk_size) { + for k in kill_interp.chunks(chunk_size) { if !seen_one { // continuation of row; this is fourth write!(w, "= {kill:?}", @@ -200,16 +244,18 @@ impl<'c, 'b:'c, 'a:'b, 'tcx:'a> dot::Labeller<'c> for Graph<'c,'b,'a,'tcx> { } } -impl<'c, 'b:'c, 'a:'b, 'tcx:'a> dot::GraphWalk<'c> for Graph<'c,'b,'a,'tcx> { +impl<'a, 'tcx, MWF> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF> + where MWF: MirWithFlowState<'tcx> +{ type Node = Node; type Edge = Edge; fn nodes(&self) -> dot::Nodes { - self.mbcx.mir.all_basic_blocks().into_cow() + self.mbcx.mir().all_basic_blocks().into_cow() } fn edges(&self) -> dot::Edges { - let mir = self.mbcx.mir; - let blocks = self.mbcx.mir.all_basic_blocks(); + let mir = self.mbcx.mir(); + let blocks = mir.all_basic_blocks(); // base initial capacity on assumption every block has at // least one outgoing edge (Which should be true for all // blocks but one, the exit-block). @@ -226,7 +272,7 @@ impl<'c, 'b:'c, 'a:'b, 'tcx:'a> dot::GraphWalk<'c> for Graph<'c,'b,'a,'tcx> { } fn target(&self, edge: &Edge) -> Node { - let mir = self.mbcx.mir; + let mir = self.mbcx.mir(); mir.basic_block_data(edge.source).terminator().successors()[edge.index] } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs new file mode 100644 index 000000000000..41fe6079526c --- /dev/null +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -0,0 +1,1024 @@ +// Copyright 2012-2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use rustc::mir::repr::{self, Mir}; + +use std::fmt::Debug; +use std::io; +use std::marker::PhantomData; +use std::mem; +use std::path::PathBuf; +use std::usize; + +use super::MirBorrowckCtxtPreDataflow; +use super::gather_moves::{Location, MoveData, MovePathData, MovePathIndex, MoveOutIndex, PathMap}; +use super::gather_moves::{MoveOut, MovePath}; +use super::DropFlagState; + +use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. + +mod graphviz; + +pub trait Dataflow { + fn dataflow(&mut self); +} + +impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> + where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> +{ + fn dataflow(&mut self) { + self.flow_state.build_sets(); + self.pre_dataflow_instrumentation().unwrap(); + self.flow_state.propagate(); + self.post_dataflow_instrumentation().unwrap(); + } +} + +struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> + where O: 'b + BitDenotation, O::Ctxt: HasMoveData<'tcx>, +{ + builder: &'b mut DataflowAnalysis<'a, 'tcx, O>, + changed: bool, +} + +impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> + where BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> +{ + fn propagate(&mut self) { + let mut temp = vec![0; self.flow_state.sets.words_per_block]; + let mut propcx = PropagationContext { + builder: self, + changed: true, + }; + while propcx.changed { + propcx.changed = false; + propcx.reset(&mut temp); + propcx.walk_cfg(&mut temp); + } + } + + fn build_sets(&mut self) { + // First we need to build the entry-, gen- and kill-sets. The + // gather_moves information provides a high-level mapping from + // mir-locations to the MoveOuts (and those correspond + // directly to gen-sets here). But we still need to figure out + // the kill-sets. + + { + let sets = &mut self.flow_state.sets.for_block(repr::START_BLOCK.index()); + self.flow_state.operator.start_block_effect(&self.ctxt, sets); + } + + for bb in self.mir.all_basic_blocks() { + let &repr::BasicBlockData { ref statements, + ref terminator, + is_cleanup: _ } = + self.mir.basic_block_data(bb); + + let sets = &mut self.flow_state.sets.for_block(bb.index()); + for j_stmt in 0..statements.len() { + self.flow_state.operator.statement_effect(&self.ctxt, sets, bb, j_stmt); + } + + if terminator.is_some() { + let stmts_len = statements.len(); + self.flow_state.operator.terminator_effect(&self.ctxt, sets, bb, stmts_len); + } + } + } +} + +fn on_all_children_bits(path_map: &PathMap, + move_paths: &MovePathData, + move_path_index: MovePathIndex, + mut each_child: Each) + where Each: FnMut(MoveOutIndex) +{ + return on_all_children_bits_recur( + path_map, move_paths, move_path_index, &mut each_child); + + fn on_all_children_bits_recur(path_map: &PathMap, + move_paths: &MovePathData, + move_path_index: MovePathIndex, + each_child: &mut Each) + where Each: FnMut(MoveOutIndex) + { + // 1. invoke `each_child` callback for all moves that directly + // influence path for `move_path_index` + for move_index in &path_map[move_path_index] { + each_child(*move_index); + } + + // 2. for each child of the path (that is named in this + // function), recur. + // + // (Unnamed children are irrelevant to dataflow; by + // definition they have no associated moves.) + let mut next_child_index = move_paths[move_path_index].first_child; + while let Some(child_index) = next_child_index { + on_all_children_bits_recur(path_map, move_paths, child_index, each_child); + next_child_index = move_paths[child_index].next_sibling; + } + } +} + +impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> + where BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> +{ + fn reset(&mut self, bits: &mut [usize]) { + let e = if BD::initial_value() {usize::MAX} else {0}; + for b in bits { + *b = e; + } + } + + fn walk_cfg(&mut self, in_out: &mut [usize]) { + let mir = self.builder.mir; + for (bb_idx, bb_data) in mir.basic_blocks.iter().enumerate() { + let builder = &mut self.builder; + { + let sets = builder.flow_state.sets.for_block(bb_idx); + debug_assert!(in_out.len() == sets.on_entry.len()); + in_out.clone_from_slice(sets.on_entry); + bitwise(in_out, sets.gen_set, &Union); + bitwise(in_out, sets.kill_set, &Subtract); + } + builder.propagate_bits_into_graph_successors_of(in_out, + &mut self.changed, + (repr::BasicBlock::new(bb_idx), bb_data)); + } + } +} + +impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> + where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> +{ + fn path(context: &str, prepost: &str, path: &str) -> PathBuf { + format!("{}_{}", context, prepost); + let mut path = PathBuf::from(path); + let new_file_name = { + let orig_file_name = path.file_name().unwrap().to_str().unwrap(); + format!("{}_{}", context, orig_file_name) + }; + path.set_file_name(new_file_name); + path + } + + fn pre_dataflow_instrumentation(&self) -> io::Result<()> { + if let Some(ref path_str) = self.print_preflow_to { + let path = Self::path(BD::name(), "preflow", path_str); + graphviz::print_borrowck_graph_to(self, &path) + } else { + Ok(()) + } + } + + fn post_dataflow_instrumentation(&self) -> io::Result<()> { + if let Some(ref path_str) = self.print_postflow_to { + let path = Self::path(BD::name(), "postflow", path_str); + graphviz::print_borrowck_graph_to(self, &path) + } else{ + Ok(()) + } + } +} + +/// Maps each block to a set of bits +#[derive(Clone, Debug)] +struct Bits { + bits: Vec, +} + +impl Bits { + fn new(init_word: usize, num_words: usize) -> Self { + Bits { bits: vec![init_word; num_words] } + } +} + +pub trait HasMoveData<'tcx> { + fn move_data(&self) -> &MoveData<'tcx>; +} + +impl<'tcx> HasMoveData<'tcx> for MoveData<'tcx> { + fn move_data(&self) -> &MoveData<'tcx> { self } +} +impl<'tcx, A, B> HasMoveData<'tcx> for (A, B, MoveData<'tcx>) { + fn move_data(&self) -> &MoveData<'tcx> { &self.2 } +} + +pub struct DataflowAnalysis<'a, 'tcx: 'a, O> + where O: BitDenotation, O::Ctxt: HasMoveData<'tcx> +{ + flow_state: DataflowState, + ctxt: O::Ctxt, + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> + where O: BitDenotation, O::Ctxt: HasMoveData<'tcx> +{ + pub fn results(self) -> (O::Ctxt, DataflowResults) { + (self.ctxt, DataflowResults(self.flow_state)) + } + + pub fn mir(&self) -> &'a Mir<'tcx> { self.mir } +} + +#[derive(Debug)] +pub struct DataflowResults(DataflowState); + +// FIXME: This type shouldn't be public, but the graphviz::MirWithFlowState trait +// references it in a method signature. Look into using `pub(crate)` to address this. +#[derive(Debug)] +pub struct DataflowState +{ + /// All the sets for the analysis. (Factored into its + /// own structure so that we can borrow it mutably + /// on its own separate from other fields.) + pub sets: AllSets, + + /// operator used to initialize, combine, and interpret bits. + operator: O, +} + +#[derive(Debug)] +pub struct AllSets { + /// Analysis bitwidth for each block. + bits_per_block: usize, + + /// Number of words associated with each block entry + /// equal to bits_per_block / usize::BITS, rounded up. + words_per_block: usize, + + /// For each block, bits generated by executing the statements in + /// the block. (For comparison, the Terminator for each block is + /// handled in a flow-specific manner during propagation.) + gen_sets: Bits, + + /// For each block, bits killed by executing the statements in the + /// block. (For comparison, the Terminator for each block is + /// handled in a flow-specific manner during propagation.) + kill_sets: Bits, + + /// For each block, bits valid on entry to the block. + on_entry_sets: Bits, +} + +pub struct BlockSets<'a> { + on_entry: &'a mut [usize], + gen_set: &'a mut [usize], + kill_set: &'a mut [usize], +} + +impl AllSets { + pub fn bits_per_block(&self) -> usize { self.bits_per_block } + pub fn for_block(&mut self, block_idx: usize) -> BlockSets { + let offset = self.words_per_block * block_idx; + let range = offset..(offset + self.words_per_block); + BlockSets { + on_entry: &mut self.on_entry_sets.bits[range.clone()], + gen_set: &mut self.gen_sets.bits[range.clone()], + kill_set: &mut self.kill_sets.bits[range], + } + } + + fn lookup_set_for<'a>(&self, sets: &'a Bits, block_idx: usize) -> &'a [usize] { + let offset = self.words_per_block * block_idx; + &sets.bits[offset..(offset + self.words_per_block)] + } + pub fn gen_set_for(&self, block_idx: usize) -> &[usize] { + self.lookup_set_for(&self.gen_sets, block_idx) + } + pub fn kill_set_for(&self, block_idx: usize) -> &[usize] { + self.lookup_set_for(&self.kill_sets, block_idx) + } + pub fn on_entry_set_for(&self, block_idx: usize) -> &[usize] { + self.lookup_set_for(&self.on_entry_sets, block_idx) + } +} + +impl DataflowState { + fn each_bit(&self, ctxt: &O::Ctxt, words: &[usize], mut f: F) + where F: FnMut(usize) { + //! Helper for iterating over the bits in a bitvector. + + let bits_per_block = self.operator.bits_per_block(ctxt); + let usize_bits: usize = mem::size_of::() * 8; + + for (word_index, &word) in words.iter().enumerate() { + if word != 0 { + let base_index = word_index * usize_bits; + for offset in 0..usize_bits { + let bit = 1 << offset; + if (word & bit) != 0 { + // NB: we round up the total number of bits + // that we store in any given bit set so that + // it is an even multiple of usize::BITS. This + // means that there may be some stray bits at + // the end that do not correspond to any + // actual value; that's why we first check + // that we are in range of bits_per_block. + let bit_index = base_index + offset as usize; + if bit_index >= bits_per_block { + return; + } else { + f(bit_index); + } + } + } + } + } + } + + pub fn interpret_set<'c>(&self, ctxt: &'c O::Ctxt, words: &[usize]) -> Vec<&'c O::Bit> { + let mut v = Vec::new(); + self.each_bit(ctxt, words, |i| { + v.push(self.operator.interpret(ctxt, i)); + }); + v + } +} + +pub trait BitwiseOperator { + /// Joins two predecessor bits together, typically either `|` or `&` + fn join(&self, pred1: usize, pred2: usize) -> usize; +} + +/// Parameterization for the precise form of data flow that is used. +pub trait DataflowOperator : BitwiseOperator { + /// Specifies the initial value for each bit in the `on_entry` set + fn initial_value() -> bool; +} + +pub trait BitDenotation: DataflowOperator { + /// Specifies what is represented by each bit in the dataflow bitvector. + type Bit; + + /// Specifies what, if any, separate context needs to be supplied for methods below. + type Ctxt; + + /// A name describing the dataflow analysis that this + /// BitDenotation is supporting. The name should be something + /// suitable for plugging in as part of a filename e.g. avoid + /// space-characters or other things that tend to look bad on a + /// file system, like slashes or periods. It is also better for + /// the name to be reasonably short, again because it will be + /// plugged into a filename. + fn name() -> &'static str; + + /// Size of each bitvector allocated for each block in the analysis. + fn bits_per_block(&self, &Self::Ctxt) -> usize; + + /// Provides the meaning of each entry in the dataflow bitvector. + /// (Mostly intended for use for better debug instrumentation.) + fn interpret<'a>(&self, &'a Self::Ctxt, idx: usize) -> &'a Self::Bit; + + /// Mutates the block-sets (the flow sets for the given + /// basic block) according to the effects that have been + /// established *prior* to entering the start block. + /// + /// (For example, establishing the call arguments.) + /// + /// (Typically this should only modify `sets.on_entry`, since the + /// gen and kill sets should reflect the effects of *executing* + /// the start block itself.) + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets); + + /// Mutates the block-sets (the flow sets for the given + /// basic block) according to the effects of evaluating statement. + /// + /// This is used, in particular, for building up the + /// "transfer-function" represnting the overall-effect of the + /// block, represented via GEN and KILL sets. + /// + /// The statement here is `idx_stmt.1`; `idx_stmt.0` is just + /// an identifying index: namely, the index of the statement + /// in the basic block. + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx_stmt: usize); + + /// Mutates the block-sets (the flow sets for the given + /// basic block) according to the effects of evaluating + /// the terminator. + /// + /// This is used, in particular, for building up the + /// "transfer-function" represnting the overall-effect of the + /// block, represented via GEN and KILL sets. + /// + /// The terminator here is `idx_term.1`; `idx_term.0` is just an + /// identifying index: namely, the number of statements in `bb` + /// itself. + /// + /// The effects applied here cannot depend on which branch the + /// terminator took. + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx_term: usize); + + /// Mutates the block-sets according to the (flow-dependent) + /// effect of a successful return from a Call terminator. + /// + /// If basic-block BB_x ends with a call-instruction that, upon + /// successful return, flows to BB_y, then this method will be + /// called on the exit flow-state of BB_x in order to set up the + /// entry flow-state of BB_y. + /// + /// This is used, in particular, as a special case during the + /// "propagate" loop where all of the basic blocks are repeatedly + /// visited. Since the effects of a Call terminator are + /// flow-dependent, the current MIR cannot encode them via just + /// GEN and KILL sets attached to the block, and so instead we add + /// this extra machinery to represent the flow-dependent effect. + /// + /// Note: as a historical artifact, this currently takes as input + /// the *entire* packed collection of bitvectors in `in_out`. We + /// might want to look into narrowing that to something more + /// specific, just to make the interface more self-documenting. + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut [usize], + call_bb: repr::BasicBlock, + dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue); +} + +impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> + where D: BitDenotation, D::Ctxt: HasMoveData<'tcx> +{ + pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &'a Mir<'tcx>, + ctxt: D::Ctxt, + denotation: D) -> Self { + let bits_per_block = denotation.bits_per_block(&ctxt); + let usize_bits = mem::size_of::() * 8; + let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits; + let num_blocks = mir.basic_blocks.len(); + let num_words = num_blocks * words_per_block; + + let entry = if D::initial_value() { usize::MAX } else {0}; + + let zeroes = Bits::new(0, num_words); + let on_entry = Bits::new(entry, num_words); + + DataflowAnalysis { flow_state: DataflowState { + sets: AllSets { + bits_per_block: bits_per_block, + words_per_block: words_per_block, + gen_sets: zeroes.clone(), + kill_sets: zeroes, + on_entry_sets: on_entry, + }, + operator: denotation, + }, + ctxt: ctxt, + mir: mir, + } + + } +} + +impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> + where D: BitDenotation, D::Ctxt: HasMoveData<'tcx> +{ + /// Propagates the bits of `in_out` into all the successors of `bb`, + /// using bitwise operator denoted by `self.operator`. + /// + /// For most blocks, this is entirely uniform. However, for blocks + /// that end with a call terminator, the effect of the call on the + /// dataflow state may depend on whether the call returned + /// successfully or unwound. + /// + /// To reflect this, the `propagate_call_return` method of the + /// `BitDenotation` mutates `in_out` when propagating `in_out` via + /// a call terminator; such mutation is performed *last*, to + /// ensure its side-effects do not leak elsewhere (e.g. into + /// unwind target). + fn propagate_bits_into_graph_successors_of( + &mut self, + in_out: &mut [usize], + changed: &mut bool, + (bb, bb_data): (repr::BasicBlock, &repr::BasicBlockData)) + { + match bb_data.terminator().kind { + repr::TerminatorKind::Return | + repr::TerminatorKind::Resume => {} + repr::TerminatorKind::Goto { ref target } | + repr::TerminatorKind::Drop { ref target, value: _, unwind: None } => { + self.propagate_bits_into_entry_set_for(in_out, changed, target); + } + repr::TerminatorKind::Drop { ref target, value: _, unwind: Some(ref unwind) } => { + self.propagate_bits_into_entry_set_for(in_out, changed, target); + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } + repr::TerminatorKind::If { ref targets, .. } => { + self.propagate_bits_into_entry_set_for(in_out, changed, &targets.0); + self.propagate_bits_into_entry_set_for(in_out, changed, &targets.1); + } + repr::TerminatorKind::Switch { ref targets, .. } | + repr::TerminatorKind::SwitchInt { ref targets, .. } => { + for target in targets { + self.propagate_bits_into_entry_set_for(in_out, changed, target); + } + } + repr::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { + if let Some(ref unwind) = *cleanup { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } + if let Some((ref dest_lval, ref dest_bb)) = *destination { + // N.B.: This must be done *last*, after all other + // propagation, as documented in comment above. + self.flow_state.operator.propagate_call_return( + &self.ctxt, in_out, bb, *dest_bb, dest_lval); + self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb); + } + } + } + } + + fn propagate_bits_into_entry_set_for(&mut self, + in_out: &[usize], + changed: &mut bool, + bb: &repr::BasicBlock) { + let entry_set = self.flow_state.sets.for_block(bb.index()).on_entry; + let set_changed = bitwise(entry_set, in_out, &self.flow_state.operator); + if set_changed { + *changed = true; + } + } +} + +// Dataflow analyses are built upon some interpretation of the +// bitvectors attached to each basic block, represented via a +// zero-sized structure. +// +// Note on PhantomData: Each interpretation will need to instantiate +// the `Bit` and `Ctxt` associated types, and in this case, those +// associated types need an associated lifetime `'tcx`. The +// interpretive structures are zero-sized, so they all need to carry a +// `PhantomData` representing how the structures relate to the `'tcx` +// lifetime. +// +// But, since all of the uses of `'tcx` are solely via instances of +// `Ctxt` that are passed into the `BitDenotation` methods, we can +// consistently use a `PhantomData` that is just a function over a +// `&Ctxt` (== `&MoveData<'tcx>). + +/// `MaybeInitializedLvals` tracks all l-values that might be +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-init: +/// // {} +/// let a = S; let b = S; let c; let d; // {a, b} +/// +/// if pred { +/// drop(a); // { b} +/// b = S; // { b} +/// +/// } else { +/// drop(b); // {a} +/// d = S; // {a, d} +/// +/// } // {a, b, d} +/// +/// c = S; // {a, b, c, d} +/// } +/// ``` +/// +/// To determine whether an l-value *must* be initialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeUninitializedLvals` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeUninitializedLvals` yields the set of +/// l-values that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct MaybeInitializedLvals<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + +/// `MaybeUninitializedLvals` tracks all l-values that might be +/// uninitialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-uninit: +/// // {a, b, c, d} +/// let a = S; let b = S; let c; let d; // { c, d} +/// +/// if pred { +/// drop(a); // {a, c, d} +/// b = S; // {a, c, d} +/// +/// } else { +/// drop(b); // { b, c, d} +/// d = S; // { b, c } +/// +/// } // {a, b, c, d} +/// +/// c = S; // {a, b, d} +/// } +/// ``` +/// +/// To determine whether an l-value *must* be uninitialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeInitializedLvals` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeInitializedLvals` yields the set of +/// l-values that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + +/// `MovingOutStatements` tracks the statements that perform moves out +/// of particular l-values. More precisely, it tracks whether the +/// *effect* of such moves (namely, the uninitialization of the +/// l-value in question) can reach some point in the control-flow of +/// the function, or if that effect is "killed" by some intervening +/// operation reinitializing that l-value. +/// +/// The resulting dataflow is a more enriched version of +/// `MaybeUninitializedLvals`. Both structures on their own only tell +/// you if an l-value *might* be uninitialized at a given point in the +/// control flow. But `MovingOutStatements` also includes the added +/// data of *which* particular statement causing the deinitialization +/// that the borrow checker's error meessage may need to report. +#[derive(Debug, Default)] +pub struct MovingOutStatements<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + +impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { + type Bit = MoveOut; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "moving_out" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.moves.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.moves[idx] + } + fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { + // no move-statements have been executed prior to function + // execution, so this method has no effect on `_sets`. + } + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) { + let &(_tcx, mir, ref move_data) = ctxt; + let stmt = &mir.basic_block_data(bb).statements[idx]; + let move_paths = &move_data.move_paths; + let loc_map = &move_data.loc_map; + let path_map = &move_data.path_map; + let rev_lookup = &move_data.rev_lookup; + + let loc = Location { block: bb, index: idx }; + debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}", + stmt, loc, &loc_map[loc]); + for move_index in &loc_map[loc] { + // Every path deinitialized by a *particular move* + // has corresponding bit, "gen'ed" (i.e. set) + // here, in dataflow vector + zero_to_one(&mut sets.gen_set, *move_index); + } + let bits_per_block = self.bits_per_block(ctxt); + match stmt.kind { + repr::StatementKind::Assign(ref lvalue, _) => { + // assigning into this `lvalue` kills all + // MoveOuts from it, and *also* all MoveOuts + // for children and associated fragment sets. + let move_path_index = rev_lookup.find(lvalue); + + sets.kill_set.set_bit(move_path_index.idx()); + on_all_children_bits(path_map, + move_paths, + move_path_index, + |moi| { + assert!(moi.idx() < bits_per_block); + sets.kill_set.set_bit(moi.idx()); + }); + } + } + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + let &(_tcx, mir, ref move_data) = ctxt; + let term = mir.basic_block_data(bb).terminator.as_ref().unwrap(); + let loc_map = &move_data.loc_map; + let loc = Location { block: bb, index: statements_len }; + debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}", + term, loc, &loc_map[loc]); + let bits_per_block = self.bits_per_block(ctxt); + for move_index in &loc_map[loc] { + assert!(move_index.idx() < bits_per_block); + zero_to_one(&mut sets.gen_set, *move_index); + } + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut [usize], + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + let move_data = &ctxt.2; + let move_path_index = move_data.rev_lookup.find(dest_lval); + let bits_per_block = self.bits_per_block(ctxt); + + in_out.clear_bit(move_path_index.idx()); + on_all_children_bits(&move_data.path_map, + &move_data.move_paths, + move_path_index, + |moi| { + assert!(moi.idx() < bits_per_block); + in_out.clear_bit(moi.idx()); + }); + } +} + +impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + state: super::DropFlagState) + { + match state { + DropFlagState::Dead => { + sets.gen_set.clear_bit(path.idx()); + sets.kill_set.set_bit(path.idx()); + } + DropFlagState::Live => { + sets.gen_set.set_bit(path.idx()); + sets.kill_set.clear_bit(path.idx()); + } + } + } +} + +impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + state: super::DropFlagState) + { + match state { + DropFlagState::Dead => { + sets.gen_set.set_bit(path.idx()); + sets.kill_set.clear_bit(path.idx()); + } + DropFlagState::Live => { + sets.gen_set.clear_bit(path.idx()); + sets.kill_set.set_bit(path.idx()); + } + } + } +} + +impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { + type Bit = MovePath<'tcx>; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "maybe_init" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.move_paths.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.move_paths[MovePathIndex::new(idx)] + } + + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) + { + super::drop_flag_effects_for_function_entry( + ctxt.0, ctxt.1, &ctxt.2, + |path, s| { + assert!(s == DropFlagState::Live); + sets.on_entry.set_bit(path.idx()); + }); + } + + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) + { + super::drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: idx }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + super::drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: statements_len }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut [usize], + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + // when a call returns successfully, that means we need to set + // the bits for that dest_lval to 1 (initialized). + let move_data = &ctxt.2; + let move_path_index = move_data.rev_lookup.find(dest_lval); + super::on_all_children_bits( + ctxt.0, ctxt.1, &ctxt.2, + move_path_index, + |mpi| { in_out.set_bit(mpi.idx()); } + ); + } +} + +impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { + type Bit = MovePath<'tcx>; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "maybe_uninit" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.move_paths.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.move_paths[MovePathIndex::new(idx)] + } + + // sets on_entry bits for Arg lvalues + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { + for e in &mut sets.on_entry[..] { *e = !0; } + + super::drop_flag_effects_for_function_entry( + ctxt.0, ctxt.1, &ctxt.2, + |path, s| { + assert!(s == DropFlagState::Live); + sets.on_entry.clear_bit(path.idx()); + }); + } + + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) + { + super::drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: idx }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + super::drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: statements_len }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut [usize], + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + // when a call returns successfully, that means we need to set + // the bits for that dest_lval to 1 (initialized). + let move_path_index = ctxt.2.rev_lookup.find(dest_lval); + super::on_all_children_bits( + ctxt.0, ctxt.1, &ctxt.2, + move_path_index, + |mpi| { in_out.clear_bit(mpi.idx()); } + ); + } +} + +fn zero_to_one(bitvec: &mut [usize], move_index: MoveOutIndex) { + let retval = bitvec.set_bit(move_index.idx()); + assert!(retval); +} + +impl<'a, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // moves from both preds are in scope + } +} + +impl<'a, 'tcx> BitwiseOperator for MaybeInitializedLvals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // "maybe" means we union effects of both preds + } +} + +impl<'a, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // "maybe" means we union effects of both preds + } +} + +// FIXME: I'm not sure it ever makes sense to use `true` for a +// DataflowOperator::initial_value implementation, because: the way +// that dataflow fixed point iteration works, you want to start at +// bottom and work your way to a fixed point. +// +// This means, for propagation across the graph, that you either want +// to start at all-zeroes and then use Union as your merge when +// propagating, or you start at all-ones and then use Intersect as +// your merge when propagating. +// +// (An alternative could be, when propagating from Block A into block +// B, to clear B's on_entry bits, and then iterate over all of B's +// immediate predecessors. This would require storing on_exit state +// for each block, however.) + +impl<'a, 'tcx> DataflowOperator for MovingOutStatements<'a, 'tcx> { + #[inline] + fn initial_value() -> bool { + false // bottom = no loans in scope by default + } +} + +impl<'a, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'tcx> { + #[inline] + fn initial_value() -> bool { + false // bottom = uninitialized + } +} + +impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> { + #[inline] + fn initial_value() -> bool { + false // bottom = uninitialized + } +} + +#[inline] +fn bitwise(out_vec: &mut [usize], + in_vec: &[usize], + op: &Op) -> bool { + assert_eq!(out_vec.len(), in_vec.len()); + let mut changed = false; + for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) { + let old_val = *out_elt; + let new_val = op.join(old_val, *in_elt); + *out_elt = new_val; + changed |= old_val != new_val; + } + changed +} + +struct Union; +impl BitwiseOperator for Union { + fn join(&self, a: usize, b: usize) -> usize { a | b } +} +struct Subtract; +impl BitwiseOperator for Subtract { + fn join(&self, a: usize, b: usize) -> usize { a & !b } +} diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 64a7dddc8aba..519e9398436b 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -19,7 +19,6 @@ use std::fmt; use std::iter; use std::ops::Index; -use super::dataflow::BitDenotation; use super::abs_domain::{AbstractElem, Lift}; // This submodule holds some newtype'd Index wrappers that are using @@ -32,7 +31,7 @@ mod indexes { macro_rules! new_index { ($Index:ident) => { - #[derive(Copy, Clone, PartialEq, Eq, Debug)] + #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct $Index(NonZero); impl $Index { @@ -56,6 +55,12 @@ mod indexes { pub use self::indexes::MovePathIndex; pub use self::indexes::MoveOutIndex; +impl self::indexes::MoveOutIndex { + pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex { + move_data.moves[self.idx()].path + } +} + /// `MovePath` is a canonicalized representation of a path that is /// moved or assigned to. /// @@ -125,6 +130,7 @@ impl<'tcx> fmt::Debug for MovePath<'tcx> { } } +#[derive(Debug)] pub struct MoveData<'tcx> { pub move_paths: MovePathData<'tcx>, pub moves: Vec, @@ -133,6 +139,7 @@ pub struct MoveData<'tcx> { pub rev_lookup: MovePathLookup<'tcx>, } +#[derive(Debug)] pub struct LocMap { /// Location-indexed (BasicBlock for outer index, index within BB /// for inner index) map to list of MoveOutIndex's. @@ -153,6 +160,7 @@ impl Index for LocMap { } } +#[derive(Debug)] pub struct PathMap { /// Path-indexed map to list of MoveOutIndex's. /// @@ -187,7 +195,7 @@ impl fmt::Debug for MoveOut { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Location { /// block where action is located pub block: BasicBlock, @@ -202,10 +210,15 @@ impl fmt::Debug for Location { } } +#[derive(Debug)] pub struct MovePathData<'tcx> { move_paths: Vec>, } +impl<'tcx> MovePathData<'tcx> { + pub fn len(&self) -> usize { self.move_paths.len() } +} + impl<'tcx> Index for MovePathData<'tcx> { type Output = MovePath<'tcx>; fn index(&self, i: MovePathIndex) -> &MovePath<'tcx> { @@ -224,6 +237,7 @@ struct MovePathDataBuilder<'a, 'tcx: 'a> { } /// Tables mapping from an l-value to its MovePathIndex. +#[derive(Debug)] pub struct MovePathLookup<'tcx> { vars: MovePathInverseMap, temps: MovePathInverseMap, @@ -272,6 +286,7 @@ impl FillTo for Vec { #[derive(Clone, Debug)] enum LookupKind { Generate, Reuse } +#[derive(Clone, Debug)] struct Lookup(LookupKind, T); impl Lookup { @@ -425,6 +440,8 @@ impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> { } fn move_path_for(&mut self, lval: &Lvalue<'tcx>) -> MovePathIndex { + debug!("move_path_for({:?})", lval); + let lookup: Lookup = self.lookup(lval); // `lookup` is either the previously assigned index or a @@ -547,7 +564,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD debug_assert!(loc_map_bb.len() == len + 1); let mut bb_ctxt = BlockContext { - tcx: tcx, + _tcx: tcx, moves: &mut moves, builder: builder, path_map: &mut path_map, @@ -608,23 +625,17 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD // example where I am seeing this arise is // `TargetDataLayout::parse(&Session)` in // `rustc::ty::layout`. - debug!("encountered Rvalue::Slice as RHS of Assign, source: {:?} \n{}", - source, { - let mut out = Vec::new(); - { - use std::io::Write; - use rustc_mir::pretty::write_mir_named; - let mut w: &mut Write = &mut out; - write_mir_named(tcx, "boo_attempt_move_out_of_slice", mir, &mut w, None).unwrap(); - } - String::from_utf8(out).unwrap() - }); + // + // this should be removed soon. + debug!("encountered Rvalue::Slice as RHS of Assign, source: {:?}", + source); } } } } } + debug!("gather_moves({:?})", bb_data.terminator()); match bb_data.terminator().kind { TerminatorKind::Goto { target: _ } | TerminatorKind::Resume => { } @@ -642,7 +653,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::If { ref cond, targets: _ } => { let source = Location { block: bb, index: bb_data.statements.len() }; - debug!("gather_moves If on_operand {:?} {:?}", cond, source); bb_ctxt.on_operand(SK::If, cond, source); } @@ -658,10 +668,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD TerminatorKind::Drop { value: ref lval, target: _, unwind: _ } => { let source = Location { block: bb, index: bb_data.statements.len() }; - debug!("gather_moves Drop on_move_out_lval {:?} {:?}", lval, source); bb_ctxt.on_move_out_lval(SK::Drop, lval, source); } - TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => { let source = Location { block: bb, index: bb_data.statements.len() }; @@ -727,7 +735,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD } struct BlockContext<'b, 'a: 'b, 'tcx: 'a> { - tcx: TyCtxt<'b, 'tcx, 'tcx>, + _tcx: TyCtxt<'b, 'tcx, 'tcx>, moves: &'b mut Vec, builder: MovePathDataBuilder<'a, 'tcx>, path_map: &'b mut Vec>, @@ -739,7 +747,6 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> { stmt_kind: StmtKind, lval: &Lvalue<'tcx>, source: Location) { - let tcx = self.tcx; let i = source.index; let index = MoveOutIndex::new(self.moves.len()); @@ -774,13 +781,3 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> { } } } - -impl<'tcx> BitDenotation for MoveData<'tcx>{ - type Bit = MoveOut; - fn bits_per_block(&self) -> usize { - self.moves.len() - } - fn interpret(&self, idx: usize) -> &Self::Bit { - &self.moves[idx] - } -} diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index bec5ae03d3d4..44a53a235286 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -10,24 +10,49 @@ use borrowck::BorrowckCtxt; -use syntax::ast; -use syntax::codemap::Span; +use syntax::ast::{self, MetaItem}; +use syntax::attr::AttrMetaMethods; +use syntax::codemap::{Span, DUMMY_SP}; +use syntax::ptr::P; use rustc::hir; use rustc::hir::intravisit::{FnKind}; +use rustc::mir::repr; use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator}; +use rustc::session::Session; +use rustc::ty::{self, TyCtxt}; mod abs_domain; mod dataflow; mod gather_moves; -mod graphviz; +// mod graphviz; -use self::dataflow::{Dataflow, DataflowState}; -use self::gather_moves::{MoveData}; +use self::dataflow::{BitDenotation}; +use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; +use self::dataflow::{HasMoveData}; +use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; +use self::gather_moves::{MoveData, MovePathIndex, Location}; +use self::gather_moves::{MovePathContent}; -pub fn borrowck_mir<'b, 'a: 'b, 'tcx: 'a>( - bcx: &'b mut BorrowckCtxt<'a, 'tcx>, +use std::fmt::Debug; + +fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option> { + for attr in attrs { + if attr.check_name("rustc_mir") { + let items = attr.meta_item_list(); + for item in items.iter().flat_map(|l| l.iter()) { + if item.check_name(name) { + return Some(item.clone()) + } + } + } + } + return None; +} + +pub fn borrowck_mir<'a, 'tcx: 'a>( + bcx: &mut BorrowckCtxt<'a, 'tcx>, fk: FnKind, _decl: &hir::FnDecl, mir: &'a Mir<'tcx>, @@ -45,29 +70,89 @@ pub fn borrowck_mir<'b, 'a: 'b, 'tcx: 'a>( } } + let tcx = bcx.tcx; + + let move_data = MoveData::gather_moves(mir, tcx); + let ctxt = (tcx, mir, move_data); + let (ctxt, flow_inits) = + do_dataflow(bcx, mir, id, attributes, ctxt, MaybeInitializedLvals::default()); + let ((_, _, move_data), flow_uninits) = + do_dataflow(bcx, mir, id, attributes, ctxt, MaybeUninitializedLvals::default()); + let mut mbcx = MirBorrowckCtxt { - flow_state: DataflowState::new_move_analysis(mir, bcx.tcx), bcx: bcx, mir: mir, node_id: id, - attributes: attributes, + move_data: move_data, + flow_inits: flow_inits, + flow_uninits: flow_uninits, }; for bb in mir.all_basic_blocks() { mbcx.process_basic_block(bb); } + debug!("borrowck_mir done"); +} + +fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + node_id: ast::NodeId, + attributes: &[ast::Attribute], + ctxt: BD::Ctxt, + bd: BD) -> (BD::Ctxt, DataflowResults) + where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> +{ + use syntax::attr::AttrMetaMethods; + + let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option { + if let Some(item) = has_rustc_mir_with(attrs, name) { + if let Some(s) = item.value_str() { + return Some(s.to_string()) + } else { + sess.span_err( + item.span, + &format!("{} attribute requires a path", item.name())); + return None; + } + } + return None; + }; + + let print_preflow_to = + name_found(tcx.sess, attributes, "borrowck_graphviz_preflow"); + let print_postflow_to = + name_found(tcx.sess, attributes, "borrowck_graphviz_postflow"); + + let mut mbcx = MirBorrowckCtxtPreDataflow { + node_id: node_id, + print_preflow_to: print_preflow_to, + print_postflow_to: print_postflow_to, + flow_state: DataflowAnalysis::new(tcx, mir, ctxt, bd), + }; + mbcx.dataflow(); + mbcx.flow_state.results() +} - debug!("borrowck_mir done"); + +pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD> + where BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> +{ + node_id: ast::NodeId, + flow_state: DataflowAnalysis<'a, 'tcx, BD>, + print_preflow_to: Option, + print_postflow_to: Option, } +#[allow(dead_code)] pub struct MirBorrowckCtxt<'b, 'a: 'b, 'tcx: 'a> { bcx: &'b mut BorrowckCtxt<'a, 'tcx>, mir: &'b Mir<'tcx>, node_id: ast::NodeId, - attributes: &'b [ast::Attribute], - flow_state: DataflowState>, + move_data: MoveData<'tcx>, + flow_inits: DataflowResults>, + flow_uninits: DataflowResults> } impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { @@ -89,3 +174,127 @@ impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { debug!("MirBorrowckCtxt::process_terminator({:?}, {:?})", bb, term); } } + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +enum DropFlagState { + Live, + Dead +} + +fn on_all_children_bits<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + move_data: &MoveData<'tcx>, + move_path_index: MovePathIndex, + mut each_child: F) + where F: FnMut(MovePathIndex) +{ + fn is_terminal_path<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + move_data: &MoveData<'tcx>, + path: MovePathIndex) -> bool + { + match move_data.move_paths[path].content { + MovePathContent::Lvalue(ref lvalue) => { + match mir.lvalue_ty(tcx, lvalue).to_ty(tcx).sty { + // don't trace paths past arrays, slices, and + // pointers. They can only be accessed while + // their parents are initialized. + // + // FIXME: we have to do something for moving + // slice patterns. + ty::TyArray(..) | ty::TySlice(..) | + ty::TyRef(..) | ty::TyRawPtr(..) => true, + _ => false + } + } + _ => true + } + } + + fn on_all_children_bits<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + move_data: &MoveData<'tcx>, + move_path_index: MovePathIndex, + each_child: &mut F) + where F: FnMut(MovePathIndex) + { + each_child(move_path_index); + + if is_terminal_path(tcx, mir, move_data, move_path_index) { + return + } + + let mut next_child_index = move_data.move_paths[move_path_index].first_child; + while let Some(child_index) = next_child_index { + on_all_children_bits(tcx, mir, move_data, child_index, each_child); + next_child_index = move_data.move_paths[child_index].next_sibling; + } + } + on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child); +} + +fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + move_data: &MoveData<'tcx>, + mut callback: F) + where F: FnMut(MovePathIndex, DropFlagState) +{ + for i in 0..(mir.arg_decls.len() as u32) { + let lvalue = repr::Lvalue::Arg(i); + let move_path_index = move_data.rev_lookup.find(&lvalue); + on_all_children_bits(tcx, mir, move_data, + move_path_index, + |moi| callback(moi, DropFlagState::Live)); + } +} + +fn drop_flag_effects_for_location<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + move_data: &MoveData<'tcx>, + loc: Location, + mut callback: F) + where F: FnMut(MovePathIndex, DropFlagState) +{ + debug!("drop_flag_effects_for_location({:?})", loc); + + // first, move out of the RHS + for mi in &move_data.loc_map[loc] { + let path = mi.move_path_index(move_data); + debug!("moving out of path {:?}", move_data.move_paths[path]); + + // don't move out of non-Copy things + if let MovePathContent::Lvalue(ref lvalue) = move_data.move_paths[path].content { + let ty = mir.lvalue_ty(tcx, lvalue).to_ty(tcx); + let empty_param_env = tcx.empty_parameter_environment(); + if !ty.moves_by_default(tcx, &empty_param_env, DUMMY_SP) { + continue; + } + } + + on_all_children_bits(tcx, mir, move_data, + path, + |moi| callback(moi, DropFlagState::Dead)) + } + + let bb = mir.basic_block_data(loc.block); + match bb.statements.get(loc.index) { + Some(stmt) => match stmt.kind { + repr::StatementKind::Assign(ref lvalue, _) => { + debug!("drop_flag_effects: assignment {:?}", stmt); + on_all_children_bits(tcx, mir, move_data, + move_data.rev_lookup.find(lvalue), + |moi| callback(moi, DropFlagState::Live)) + } + }, + None => { + // terminator - no move-ins except for function return edge + let term = bb.terminator(); + debug!("drop_flag_effects: terminator {:?}", term); + } + } +} From 60bf92ce6ea2f892e4dcb8f32ddfc8a37bee3055 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 11 May 2016 21:54:12 +0200 Subject: [PATCH 016/179] Adding magic `rustc_peek` intrinsic that other code can repurpose to its own needs based on attributes attached to the function where it appears. --- src/libcore/intrinsics.rs | 10 ++++++++++ src/librustc_typeck/check/intrinsic.rs | 1 + 2 files changed, 11 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8a9f662bf83a..225929fb350b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -168,6 +168,16 @@ extern "rust-intrinsic" { pub fn atomic_singlethreadfence_rel(); pub fn atomic_singlethreadfence_acqrel(); + /// Magic intrinsic that derives its meaning from attributes + /// attached to the function. + /// + /// For example, dataflow uses this to inject static assertions so + /// that `rustc_oeek(potentially_uninitialized)` would actually + /// double-check that dataflow did indeed compute that it is + /// uninitialized at that point in the control flow. + #[cfg(not(stage0))] + pub fn rustc_peek(_: T) -> T; + /// Aborts the execution of the process. pub fn abort() -> !; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index c02139140aed..f120e38630b8 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -117,6 +117,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { param(ccx, 0)) ], ccx.tcx.types.usize) } + "rustc_peek" => (1, vec![param(ccx, 0)], param(ccx, 0)), "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)), "uninit" => (1, Vec::new(), param(ccx, 0)), "forget" => (1, vec!( param(ccx, 0) ), tcx.mk_nil()), From 1ec12b112dd78b41d41dd4677fbbf79ed6e26e94 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 11 May 2016 22:03:57 +0200 Subject: [PATCH 017/179] Add ability to unit-test dataflow results via `rustc_peek` intrinsic. (The static semantics of `rustc_peek` is derived from attributes attached to the function being compiled; in this case, `rustc_peek(&expr)` observes the dataflow state for the l-value `expr`.) --- .../borrowck/mir/dataflow/sanity_check.rs | 193 ++++++++++++++++++ src/librustc_borrowck/borrowck/mir/mod.rs | 18 +- 2 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs new file mode 100644 index 000000000000..f74fb4ebadc2 --- /dev/null +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -0,0 +1,193 @@ +// Copyright 2012-2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::abi::{Abi}; +use syntax::ast; + +use rustc::ty::{self, TyCtxt}; +use rustc::mir::repr::{self, Mir}; + +use bitslice::BitSlice; + +use super::super::gather_moves::MovePath; +use super::{bitwise, Union, Subtract}; +use super::BitDenotation; +use super::DataflowResults; +use super::HasMoveData; + +pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + id: ast::NodeId, + _attributes: &[ast::Attribute], + flow_ctxt: &O::Ctxt, + results: &DataflowResults) + where O: BitDenotation>, O::Ctxt: HasMoveData<'tcx> +{ + debug!("sanity_check_via_rustc_peek id: {:?}", id); + // FIXME: this is not DRY. Figure out way to abstract this and + // `dataflow::build_sets`. (But see note below about how the + // behavior of this traversal is a bit different than that + // performed by `build_sets`.) + + let blocks = mir.all_basic_blocks(); + 'next_block: for bb in blocks { + let bb_data = mir.basic_block_data(bb); + let &repr::BasicBlockData { ref statements, + ref terminator, + is_cleanup: _ } = bb_data; + + let (args, span) = if let Some(repr::Terminator { ref kind, span, .. }) = *terminator { + if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind + { + if let repr::Operand::Constant(ref func) = *oper + { + if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty + { + let name = tcx.item_name(def_id); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + if name.as_str() == "rustc_peek" { + (args, span) + } else { + continue; + } + } else { + continue; + } + } else { + continue; + } + } else { + continue; + } + } else { + continue; + } + } else { + continue; + }; + assert!(args.len() == 1); + let peek_arg_lval = match args[0] { + repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => { + lval + } + repr::Operand::Consume(_) => { + bug!("dataflow::sanity_check cannot feed a non-temp to rustc_peek."); + } + repr::Operand::Constant(_) => { + bug!("dataflow::sanity_check cannot feed a constant to rustc_peek."); + } + }; + + let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned(); + let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned(); + let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned(); + + let move_data = flow_ctxt.move_data(); + + // Emulate effect of all statements in the block up to (but + // not including) the assignment to `peek_arg_lval`. Do *not* + // include terminator (since we are peeking the state of the + // argument at time immediate preceding Call to `rustc_peek`). + + let mut sets = super::BlockSets { on_entry: &mut entry[..], + gen_set: &mut gen[..], + kill_set: &mut kill[..] }; + // Unfortunately if we just re-do the same thing that dataflow does, then + // it will always appear like Lvalues are initialized; e.g. in + // a case like: + // + // + // tmp13 = var1; + // tmp14 = &tmp13; + // rustc_peek(tmp14) + // + // The gen_set for normal dataflow would treat tmp13 as + // initialized, even though it's source expression is + // uninitialized. + // + // Work around this for rustc_peek by explicitly propagating + // the relevant bitvector state when computing the effect of a + // statement. + + for (j, stmt) in statements.iter().enumerate() { + debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); + let (lvalue, rvalue) = match stmt.kind { + repr::StatementKind::Assign(ref lvalue, ref rvalue) => { + (lvalue, rvalue) + } + }; + + if lvalue == peek_arg_lval { + if let repr::Rvalue::Ref(_, + repr::BorrowKind::Shared, + ref peeking_at_lval) = *rvalue { + // Okay, our search is over. + let peek_mpi = move_data.rev_lookup.find(peeking_at_lval); + let bit_state = sets.on_entry.get_bit(peek_mpi.idx()); + debug!("rustc_peek({:?} = &{:?}) bit_state: {}", + lvalue, peeking_at_lval, bit_state); + if !bit_state { + tcx.sess.span_err(span, &format!("rustc_peek: bit not set")); + } + continue 'next_block; + } else { + // Our search should have been over, but the input + // does not match expectations of `rustc_peek` for + // this sanity_check. + tcx.sess.span_err(span, &format!("rustc_peek: argument expression \ + must be immediate borrow of form `&expr`")); + } + } + + enum Effect<'a, 'tcx:'a> { Propagate(&'a repr::Lvalue<'tcx>), Compute } + let lvalue_effect: Effect = match *rvalue { + // tmp = rhs + repr::Rvalue::Use(repr::Operand::Consume(ref rhs_lval)) => + Effect::Propagate(rhs_lval), + + repr::Rvalue::Use(repr::Operand::Constant(_)) => + Effect::Compute, + + _ => { + // (fall back to BitDenotation for all other kinds of Rvalues + Effect::Compute + } + }; + + let lhs_mpi = move_data.rev_lookup.find(lvalue); + + if let Effect::Propagate(rhs_lval) = lvalue_effect { + let rhs_mpi = move_data.rev_lookup.find(rhs_lval); + let state = sets.on_entry.get_bit(rhs_mpi.idx()); + debug!("rustc_peek: propagate into lvalue {:?} ({:?}) from rhs: {:?} state: {}", + lvalue, lhs_mpi, rhs_lval, state); + if state { + sets.on_entry.set_bit(lhs_mpi.idx()); + } else { + sets.on_entry.clear_bit(lhs_mpi.idx()); + } + } else { + debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}", + lvalue, lhs_mpi, stmt); + // reset GEN and KILL sets before emulating their effect. + for e in &mut sets.gen_set[..] { *e = 0; } + for e in &mut sets.kill_set[..] { *e = 0; } + results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j); + bitwise(sets.on_entry, sets.gen_set, &Union); + bitwise(sets.on_entry, sets.kill_set, &Subtract); + } + } + + tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ + anticipated pattern; note that \ + rustc_peek expects input of \ + form `&expr`")); + } +} diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 44a53a235286..ce49e9fc93d6 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -75,9 +75,21 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( let move_data = MoveData::gather_moves(mir, tcx); let ctxt = (tcx, mir, move_data); let (ctxt, flow_inits) = - do_dataflow(bcx, mir, id, attributes, ctxt, MaybeInitializedLvals::default()); - let ((_, _, move_data), flow_uninits) = - do_dataflow(bcx, mir, id, attributes, ctxt, MaybeUninitializedLvals::default()); + do_dataflow(tcx, mir, id, attributes, ctxt, MaybeInitializedLvals::default()); + let (ctxt, flow_uninits) = + do_dataflow(tcx, mir, id, attributes, ctxt, MaybeUninitializedLvals::default()); + + if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() { + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_inits); + } + if has_rustc_mir_with(attributes, "rustc_peek_maybe_uninit").is_some() { + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_uninits); + } + let move_data = ctxt.2; + + if has_rustc_mir_with(attributes, "stop_after_dataflow").is_some() { + bcx.tcx.sess.fatal("stop_after_dataflow ended compilation"); + } let mut mbcx = MirBorrowckCtxt { bcx: bcx, From a629abd6a2e9f671fc6ae12f76da02565c346195 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 6 May 2016 18:48:48 +0200 Subject: [PATCH 018/179] Little unit tests for MIR dataflow analysis. These use new `rustc_peek` (whose semantics is driven by attribute attached to fn). --- .../borrowck/mir/dataflow/mod.rs | 3 + src/test/compile-fail/mir-dataflow/README.md | 53 +++++++++++++++ src/test/compile-fail/mir-dataflow/inits-1.rs | 65 +++++++++++++++++++ .../compile-fail/mir-dataflow/uninits-1.rs | 63 ++++++++++++++++++ .../compile-fail/mir-dataflow/uninits-2.rs | 36 ++++++++++ 5 files changed, 220 insertions(+) create mode 100644 src/test/compile-fail/mir-dataflow/README.md create mode 100644 src/test/compile-fail/mir-dataflow/inits-1.rs create mode 100644 src/test/compile-fail/mir-dataflow/uninits-1.rs create mode 100644 src/test/compile-fail/mir-dataflow/uninits-2.rs diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 41fe6079526c..af31d9299446 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -25,7 +25,10 @@ use super::DropFlagState; use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. +pub use self::sanity_check::sanity_check_via_rustc_peek; + mod graphviz; +mod sanity_check; pub trait Dataflow { fn dataflow(&mut self); diff --git a/src/test/compile-fail/mir-dataflow/README.md b/src/test/compile-fail/mir-dataflow/README.md new file mode 100644 index 000000000000..b3e0315bb823 --- /dev/null +++ b/src/test/compile-fail/mir-dataflow/README.md @@ -0,0 +1,53 @@ +This directory contains unit tests for the MIR-based dataflow +analysis. + +These unit tests check the dataflow analysis by embedding calls to a +special `rustc_peek` intrinsic within the code, in tandem with an +attribute `#[rustc_mir(rustc_peek_maybe_init)]` (*). With that +attribute in place, `rustc_peek` calls are a signal to the compiler to +lookup the computed dataflow state for the Lvalue corresponding to the +argument expression being fed to `rustc_peek`. If the dataflow state +for that Lvalue is a 1-bit at that point in the control flow, then no +error is emitted by the compiler at that point; if it is a 0-bit, then +that invocation of `rustc_peek` will emit an error with the message +"rustc_peek: bit not set". + +(*): Or `#[rustc_mir(rustc_peek_maybe_uninit)]`, and perhaps other +variants in the future. + +The end effect is that one can write unit tests for MIR dataflow that +perform simple-queries of the computed dataflow state, and the tests +should be able to be robust in the face of changes to how MIR is +represented or constructed. + +---- + +Sometimes understanding the dataflow results is difficult without +looking at the actual MIR control-flow graph being processed with the +corresponding GEN and KILL sets. + +For a graphviz-rendering with dataflow annotations, add the attribute +`#[rustc_mir(borrowck_graphviz_postflow="/path/to/suffix.dot")]` to +the function in question. (You can change the content of +`"suffix.dot"` to control the filenames used for the output). This +will generate a separate file for each dataflow analysis, adding a +prefix (corresponding to the name of the analysis) to the filename in +each generated output path. + + * For example, the above attribute will currently cause two files to + be generated: `/path/to/maybe_init_suffix.dot` and + `/path/to/maybe_uninit_suffix.dot`. + + * The generated `.dot` file shows both the computed dataflow results + on *entry* to each block, as well as the gen- and kill-sets that + were so-called "transfer functions" summarizing the effect of each + basic block. + + * (In addition to the `borrowck_graphviz_postflow` attribute-key + noted above, there is also `borrowck_graphviz_preflow`; it has the + same interface and generates the same set of files, but it renders + the dataflow state after building the gen- and kill-sets but + *before* running the dataflow analysis itself, so each entry-set is + just the initial default state for that dataflow analysis. This is + less useful for understanding the error message output in these + tests.) diff --git a/src/test/compile-fail/mir-dataflow/inits-1.rs b/src/test/compile-fail/mir-dataflow/inits-1.rs new file mode 100644 index 000000000000..949688098f62 --- /dev/null +++ b/src/test/compile-fail/mir-dataflow/inits-1.rs @@ -0,0 +1,65 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// General test of maybe_inits state computed by MIR dataflow. + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir_borrowck] +#[rustc_mir(rustc_peek_maybe_init,stop_after_dataflow)] +fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { + let ret; + // `ret` starts off uninitialized, so we get an error report here. + unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set + + // All function formal parameters start off initialized. + + unsafe { rustc_peek(&x) }; + unsafe { rustc_peek(&y) }; + unsafe { rustc_peek(&z) }; + + ret = if test { + ::std::mem::replace(x, y) + } else { + z = y; + z + }; + + + // `z` may be initialized here. + unsafe { rustc_peek(&z); } + + // `y` is definitely uninitialized here. + unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set + + // `x` is still (definitely) initialized (replace above is a reborrow). + unsafe { rustc_peek(&x); } + + ::std::mem::drop(x); + + // `x` is *definitely* uninitialized here + unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set + + // `ret` is now definitely initialized (via `if` above). + unsafe { rustc_peek(&ret); } + + ret +} + +fn main() { + foo(true, &mut S(13), S(14), S(15)); + foo(false, &mut S(13), S(14), S(15)); +} diff --git a/src/test/compile-fail/mir-dataflow/uninits-1.rs b/src/test/compile-fail/mir-dataflow/uninits-1.rs new file mode 100644 index 000000000000..c13daae24f35 --- /dev/null +++ b/src/test/compile-fail/mir-dataflow/uninits-1.rs @@ -0,0 +1,63 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// General test of maybe_uninits state computed by MIR dataflow. + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir_borrowck] +#[rustc_mir(rustc_peek_maybe_uninit,stop_after_dataflow)] +fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { + let ret; + // `ret` starts off uninitialized + unsafe { rustc_peek(&ret); } + + // All function formal parameters start off initialized. + + unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set + unsafe { rustc_peek(&y) }; //~ ERROR rustc_peek: bit not set + unsafe { rustc_peek(&z) }; //~ ERROR rustc_peek: bit not set + + ret = if test { + ::std::mem::replace(x, y) + } else { + z = y; + z + }; + + // `z` may be uninitialized here. + unsafe { rustc_peek(&z); } + + // `y` is definitely uninitialized here. + unsafe { rustc_peek(&y); } + + // `x` is still (definitely) initialized (replace above is a reborrow). + unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set + + ::std::mem::drop(x); + + // `x` is *definitely* uninitialized here + unsafe { rustc_peek(&x); } + + // `ret` is now definitely initialized (via `if` above). + unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set + + ret +} +fn main() { + foo(true, &mut S(13), S(14), S(15)); + foo(false, &mut S(13), S(14), S(15)); +} diff --git a/src/test/compile-fail/mir-dataflow/uninits-2.rs b/src/test/compile-fail/mir-dataflow/uninits-2.rs new file mode 100644 index 000000000000..a2869da7eb35 --- /dev/null +++ b/src/test/compile-fail/mir-dataflow/uninits-2.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// General test of maybe_uninits state computed by MIR dataflow. + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir_borrowck] +#[rustc_mir(rustc_peek_maybe_uninit,stop_after_dataflow,borrowck_graphviz_postflow="/tmp/uninits-2.dot")] +fn foo(x: &mut S) { + // `x` is initialized here, so maybe-uninit bit is 0. + + unsafe { *rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set + + ::std::mem::drop(x); + + // `x` definitely uninitialized here, so maybe-uninit bit is 1. + unsafe { rustc_peek(&x) }; +} +fn main() { + foo(&mut S(13)); + foo(&mut S(13)); +} From 6bba7be20136b3fd1c2aa447e46c3620401f15a0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 13 May 2016 20:44:12 +0200 Subject: [PATCH 019/179] `DefinitelyInitializedLvals` dataflow op (goal: move away from `MaybeUninitializedLvals`) --- .../borrowck/mir/dataflow/mod.rs | 161 ++++++++++++++++-- src/librustc_borrowck/borrowck/mir/mod.rs | 6 + .../compile-fail/mir-dataflow/def-inits-1.rs | 63 +++++++ 3 files changed, 220 insertions(+), 10 deletions(-) create mode 100644 src/test/compile-fail/mir-dataflow/def-inits-1.rs diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index af31d9299446..4cf739396e7f 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -661,6 +661,53 @@ pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> { phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> } +/// `DefinitelyInitializedLvals` tracks all l-values that are definitely +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// FIXME: Note that once flow-analysis is complete, this should be +/// the set-complement of MaybeUninitializedLvals; thus we can get rid +/// of one or the other of these two. I'm inclined to get rid of +/// MaybeUninitializedLvals, simply because the sets will tend to be +/// smaller in this analysis and thus easier for humans to process +/// when debugging. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // definite-init: +/// // { } +/// let a = S; let b = S; let c; let d; // {a, b } +/// +/// if pred { +/// drop(a); // { b, } +/// b = S; // { b, } +/// +/// } else { +/// drop(b); // {a, } +/// d = S; // {a, d} +/// +/// } // { } +/// +/// c = S; // { c } +/// } +/// ``` +/// +/// To determine whether an l-value *may* be uninitialized at a +/// particular control-flow point, one can take the set-complement +/// of this data. +/// +/// Similarly, at a given `drop` statement, the set-difference between +/// this data and `MaybeInitializedLvals` yields the set of l-values +/// that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + /// `MovingOutStatements` tracks the statements that perform moves out /// of particular l-values. More precisely, it tracks whether the /// *effect* of such moves (namely, the uninitialization of the @@ -809,6 +856,23 @@ impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { } } +impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + state: super::DropFlagState) + { + match state { + DropFlagState::Dead => { + sets.gen_set.clear_bit(path.idx()); + sets.kill_set.set_bit(path.idx()); + } + DropFlagState::Live => { + sets.gen_set.set_bit(path.idx()); + sets.kill_set.clear_bit(path.idx()); + } + } + } +} + impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { type Bit = MovePath<'tcx>; type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); @@ -940,6 +1004,72 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { } } +impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { + type Bit = MovePath<'tcx>; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "definite_init" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.move_paths.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.move_paths[MovePathIndex::new(idx)] + } + + // sets on_entry bits for Arg lvalues + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { + for e in &mut sets.on_entry[..] { *e = 0; } + + super::drop_flag_effects_for_function_entry( + ctxt.0, ctxt.1, &ctxt.2, + |path, s| { + assert!(s == DropFlagState::Live); + sets.on_entry.set_bit(path.idx()); + }); + } + + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) + { + super::drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: idx }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + super::drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: statements_len }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut [usize], + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + // when a call returns successfully, that means we need to set + // the bits for that dest_lval to 1 (initialized). + let move_path_index = ctxt.2.rev_lookup.find(dest_lval); + super::on_all_children_bits( + ctxt.0, ctxt.1, &ctxt.2, + move_path_index, + |mpi| { in_out.set_bit(mpi.idx()); } + ); + } +} + fn zero_to_one(bitvec: &mut [usize], move_index: MoveOutIndex) { let retval = bitvec.set_bit(move_index.idx()); assert!(retval); @@ -966,21 +1096,25 @@ impl<'a, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'tcx> { } } -// FIXME: I'm not sure it ever makes sense to use `true` for a -// DataflowOperator::initial_value implementation, because: the way -// that dataflow fixed point iteration works, you want to start at -// bottom and work your way to a fixed point. +impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 & pred2 // "definitely" means we intersect effects of both preds + } +} + +// FIXME: `DataflowOperator::initial_value` should be named +// `bottom_value`. The way that dataflow fixed point iteration works, +// you want to start at bottom and work your way to a fixed point. +// This needs to include the detail that the control-flow merges will +// apply the `join` operator above to current state (which starts at +// that bottom value). // // This means, for propagation across the graph, that you either want // to start at all-zeroes and then use Union as your merge when // propagating, or you start at all-ones and then use Intersect as // your merge when propagating. -// -// (An alternative could be, when propagating from Block A into block -// B, to clear B's on_entry bits, and then iterate over all of B's -// immediate predecessors. This would require storing on_exit state -// for each block, however.) - + impl<'a, 'tcx> DataflowOperator for MovingOutStatements<'a, 'tcx> { #[inline] fn initial_value() -> bool { @@ -1002,6 +1136,13 @@ impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> { } } +impl<'a, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'tcx> { + #[inline] + fn initial_value() -> bool { + true // bottom = initialized + } +} + #[inline] fn bitwise(out_vec: &mut [usize], in_vec: &[usize], diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index ce49e9fc93d6..405647aec026 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -32,6 +32,7 @@ use self::dataflow::{BitDenotation}; use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; use self::dataflow::{HasMoveData}; use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; +use self::dataflow::{DefinitelyInitializedLvals}; use self::gather_moves::{MoveData, MovePathIndex, Location}; use self::gather_moves::{MovePathContent}; @@ -78,6 +79,8 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( do_dataflow(tcx, mir, id, attributes, ctxt, MaybeInitializedLvals::default()); let (ctxt, flow_uninits) = do_dataflow(tcx, mir, id, attributes, ctxt, MaybeUninitializedLvals::default()); + let (ctxt, flow_def_inits) = + do_dataflow(tcx, mir, id, attributes, ctxt, DefinitelyInitializedLvals::default()); if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() { dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_inits); @@ -85,6 +88,9 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( if has_rustc_mir_with(attributes, "rustc_peek_maybe_uninit").is_some() { dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_uninits); } + if has_rustc_mir_with(attributes, "rustc_peek_definite_init").is_some() { + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_def_inits); + } let move_data = ctxt.2; if has_rustc_mir_with(attributes, "stop_after_dataflow").is_some() { diff --git a/src/test/compile-fail/mir-dataflow/def-inits-1.rs b/src/test/compile-fail/mir-dataflow/def-inits-1.rs new file mode 100644 index 000000000000..a133ddc15f1a --- /dev/null +++ b/src/test/compile-fail/mir-dataflow/def-inits-1.rs @@ -0,0 +1,63 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// General test of maybe_uninits state computed by MIR dataflow. + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] + +use std::intrinsics::rustc_peek; +use std::mem::{drop, replace}; + +struct S(i32); + +#[rustc_mir_borrowck] +#[rustc_mir(rustc_peek_definite_init,stop_after_dataflow)] +fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S { + let ret; + // `ret` starts off uninitialized + unsafe { rustc_peek(&ret); } //~ ERROR rustc_peek: bit not set + + // All function formal parameters start off initialized. + + unsafe { rustc_peek(&x) }; + unsafe { rustc_peek(&y) }; + unsafe { rustc_peek(&z) }; + + ret = if test { + ::std::mem::replace(x, y) + } else { + z = y; + z + }; + + // `z` may be uninitialized here. + unsafe { rustc_peek(&z); } //~ ERROR rustc_peek: bit not set + + // `y` is definitely uninitialized here. + unsafe { rustc_peek(&y); } //~ ERROR rustc_peek: bit not set + + // `x` is still (definitely) initialized (replace above is a reborrow). + unsafe { rustc_peek(&x); } + + ::std::mem::drop(x); + + // `x` is *definitely* uninitialized here + unsafe { rustc_peek(&x); } //~ ERROR rustc_peek: bit not set + + // `ret` is now definitely initialized (via `if` above). + unsafe { rustc_peek(&ret); } + + ret +} +fn main() { + foo(true, &mut S(13), S(14), S(15)); + foo(false, &mut S(13), S(14), S(15)); +} From 28ed852163f026aa4b9a4cb2b6caae056e6d8728 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 16 May 2016 17:10:44 +0200 Subject: [PATCH 020/179] core::intrinsics: fix typo noted during review. --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 225929fb350b..0350824ee359 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -172,7 +172,7 @@ extern "rust-intrinsic" { /// attached to the function. /// /// For example, dataflow uses this to inject static assertions so - /// that `rustc_oeek(potentially_uninitialized)` would actually + /// that `rustc_peek(potentially_uninitialized)` would actually /// double-check that dataflow did indeed compute that it is /// uninitialized at that point in the control flow. #[cfg(not(stage0))] From 537c898c4d5c80add76e33759d6a41ccb447b18e Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 16 May 2016 14:26:49 +1000 Subject: [PATCH 021/179] Deprecate {f32,f64}::abs_sub. The abs_sub name is misleading: the function actually computes the positive difference (`fdim` in C), not the `(x - y).abs()` that *many* people expect from the name. This function can be replaced with just `(x - y).max(0.0)`, mirroring the `abs` version, but this behaves differently with NAN: `NAN.max(0.0) == 0.0`, while `NAN.positive_diff(0.0) == NAN`. People who absolutely need that behaviour can use the C function directly and/or talk to the libs team (we haven't encountered a concrete use-case for this functionality). Closes #30315. --- src/libstd/num/f32.rs | 39 ++++++++++++++------------------------- src/libstd/num/f64.rs | 31 ++++++++++--------------------- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 94aa3d6b513e..c0031aa42e60 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -829,6 +829,13 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[rustc_deprecated(since = "1.10.0", + reason = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` (also \ + known as `fdimf` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdimf`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too).")] pub fn abs_sub(self, other: f32) -> f32 { unsafe { cmath::fdimf(self, other) } } @@ -939,7 +946,7 @@ impl f32 { /// let f = f32::consts::PI / 2.0; /// /// // asin(sin(pi/2)) - /// let abs_difference = f.sin().asin().abs_sub(f32::consts::PI / 2.0); + /// let abs_difference = (f.sin().asin() - f32::consts::PI / 2.0).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -959,7 +966,7 @@ impl f32 { /// let f = f32::consts::PI / 4.0; /// /// // acos(cos(pi/4)) - /// let abs_difference = f.cos().acos().abs_sub(f32::consts::PI / 4.0); + /// let abs_difference = (f.cos().acos() - f32::consts::PI / 4.0).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -978,7 +985,7 @@ impl f32 { /// let f = 1.0f32; /// /// // atan(tan(1)) - /// let abs_difference = f.tan().atan().abs_sub(1.0); + /// let abs_difference = (f.tan().atan() - 1.0).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -1048,7 +1055,7 @@ impl f32 { /// let x = 7.0f64; /// /// // e^(ln(7)) - 1 - /// let abs_difference = x.ln().exp_m1().abs_sub(6.0); + /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -1108,7 +1115,7 @@ impl f32 { /// let f = x.cosh(); /// // Solving cosh() at 1 gives this result /// let g = (e*e + 1.0)/(2.0*e); - /// let abs_difference = f.abs_sub(g); + /// let abs_difference = (f - g).abs(); /// /// // Same result /// assert!(abs_difference <= f32::EPSILON); @@ -1191,9 +1198,9 @@ impl f32 { /// let e = f32::consts::E; /// let f = e.tanh().atanh(); /// - /// let abs_difference = f.abs_sub(e); + /// let abs_difference = (f - e).abs(); /// - /// assert!(abs_difference <= f32::EPSILON); + /// assert!(abs_difference <= 1e-5); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1747,24 +1754,6 @@ mod tests { assert!(match nan.frexp() { (x, _) => x.is_nan() }) } - #[test] - fn test_abs_sub() { - assert_eq!((-1f32).abs_sub(1f32), 0f32); - assert_eq!(1f32.abs_sub(1f32), 0f32); - assert_eq!(1f32.abs_sub(0f32), 1f32); - assert_eq!(1f32.abs_sub(-1f32), 2f32); - assert_eq!(NEG_INFINITY.abs_sub(0f32), 0f32); - assert_eq!(INFINITY.abs_sub(1f32), INFINITY); - assert_eq!(0f32.abs_sub(NEG_INFINITY), INFINITY); - assert_eq!(0f32.abs_sub(INFINITY), 0f32); - } - - #[test] - fn test_abs_sub_nowin() { - assert!(NAN.abs_sub(-1f32).is_nan()); - assert!(1f32.abs_sub(NAN).is_nan()); - } - #[test] fn test_asinh() { assert_eq!(0.0f32.asinh(), 0.0f32); diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 2beffb64d3dc..1a46d9a38957 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -718,9 +718,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } - } + #[rustc_deprecated(since = "1.10.0", + reason = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` (also \ + known as `fdim` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdim`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too).")] + pub fn abs_sub(self, other: f64) -> f64 { + unsafe { cmath::fdim(self, other) } + } /// Takes the cubic root of a number. /// @@ -1642,24 +1649,6 @@ mod tests { assert!(match nan.frexp() { (x, _) => x.is_nan() }) } - #[test] - fn test_abs_sub() { - assert_eq!((-1f64).abs_sub(1f64), 0f64); - assert_eq!(1f64.abs_sub(1f64), 0f64); - assert_eq!(1f64.abs_sub(0f64), 1f64); - assert_eq!(1f64.abs_sub(-1f64), 2f64); - assert_eq!(NEG_INFINITY.abs_sub(0f64), 0f64); - assert_eq!(INFINITY.abs_sub(1f64), INFINITY); - assert_eq!(0f64.abs_sub(NEG_INFINITY), INFINITY); - assert_eq!(0f64.abs_sub(INFINITY), 0f64); - } - - #[test] - fn test_abs_sub_nowin() { - assert!(NAN.abs_sub(-1f64).is_nan()); - assert!(1f64.abs_sub(NAN).is_nan()); - } - #[test] fn test_asinh() { assert_eq!(0.0f64.asinh(), 0.0f64); From b4cbffe2b9c2c16375dad661912b5a79d4718c96 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 May 2016 08:37:36 +0200 Subject: [PATCH 022/179] Fix comments in `mir::dataflow::sanity_check`. --- .../borrowck/mir/dataflow/sanity_check.rs | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index f74fb4ebadc2..39eb0c33dfbc 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -22,6 +22,22 @@ use super::BitDenotation; use super::DataflowResults; use super::HasMoveData; +/// This function scans `mir` for all calls to the intrinsic +/// `rustc_peek` that have the expression form `rustc_peek(&expr)`. +/// +/// For each such call, determines what the dataflow bit-state is for +/// the L-value corresponding to `expr`; if the bit-state is a 1, then +/// that call to `rustc_peek` is ignored by the sanity check. If the +/// bit-state is a 0, then this pass emits a error message saying +/// "rustc_peek: bit not set". +/// +/// The intention is that one can write unit tests for dataflow by +/// putting code into a compile-fail test and using `rustc_peek` to +/// make observations about the results of dataflow static analyses. +/// +/// (If there are any calls to `rustc_peek` that do not match the +/// expression form above, then that emits an error as well, but those +/// errors are not intended to be used for unit tests.) pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, id: ast::NodeId, @@ -32,9 +48,8 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { debug!("sanity_check_via_rustc_peek id: {:?}", id); // FIXME: this is not DRY. Figure out way to abstract this and - // `dataflow::build_sets`. (But see note below about how the - // behavior of this traversal is a bit different than that - // performed by `build_sets`.) + // `dataflow::build_sets`. (But note it is doing non-standard + // stuff, so such generalization may not be realistic.) let blocks = mir.all_basic_blocks(); 'next_block: for bb in blocks { @@ -99,22 +114,6 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut sets = super::BlockSets { on_entry: &mut entry[..], gen_set: &mut gen[..], kill_set: &mut kill[..] }; - // Unfortunately if we just re-do the same thing that dataflow does, then - // it will always appear like Lvalues are initialized; e.g. in - // a case like: - // - // - // tmp13 = var1; - // tmp14 = &tmp13; - // rustc_peek(tmp14) - // - // The gen_set for normal dataflow would treat tmp13 as - // initialized, even though it's source expression is - // uninitialized. - // - // Work around this for rustc_peek by explicitly propagating - // the relevant bitvector state when computing the effect of a - // statement. for (j, stmt) in statements.iter().enumerate() { debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); From f9e6530514cc9d16f6c4b99360874eecc3cb8cf2 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 May 2016 08:44:24 +0200 Subject: [PATCH 023/179] Escape asterix in markdown file to side-step it being interpreted as emphasis. --- src/test/compile-fail/mir-dataflow/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/mir-dataflow/README.md b/src/test/compile-fail/mir-dataflow/README.md index b3e0315bb823..eaf2cf7f8059 100644 --- a/src/test/compile-fail/mir-dataflow/README.md +++ b/src/test/compile-fail/mir-dataflow/README.md @@ -3,7 +3,7 @@ analysis. These unit tests check the dataflow analysis by embedding calls to a special `rustc_peek` intrinsic within the code, in tandem with an -attribute `#[rustc_mir(rustc_peek_maybe_init)]` (*). With that +attribute `#[rustc_mir(rustc_peek_maybe_init)]` (\*). With that attribute in place, `rustc_peek` calls are a signal to the compiler to lookup the computed dataflow state for the Lvalue corresponding to the argument expression being fed to `rustc_peek`. If the dataflow state From 7263648e00e215afcb942cee6b76c4fc80471436 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 May 2016 09:06:18 +0200 Subject: [PATCH 024/179] `mir::dataflow::sanity_check`: removed hackish `tmp = val` propagation code. (it was an artifact of an earlier design of the `rustc_peek` API, but its totally unnecessary now.) --- .../borrowck/mir/dataflow/sanity_check.rs | 43 ++++--------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 39eb0c33dfbc..b45b79229128 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -145,43 +145,16 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - enum Effect<'a, 'tcx:'a> { Propagate(&'a repr::Lvalue<'tcx>), Compute } - let lvalue_effect: Effect = match *rvalue { - // tmp = rhs - repr::Rvalue::Use(repr::Operand::Consume(ref rhs_lval)) => - Effect::Propagate(rhs_lval), - - repr::Rvalue::Use(repr::Operand::Constant(_)) => - Effect::Compute, - - _ => { - // (fall back to BitDenotation for all other kinds of Rvalues - Effect::Compute - } - }; - let lhs_mpi = move_data.rev_lookup.find(lvalue); - if let Effect::Propagate(rhs_lval) = lvalue_effect { - let rhs_mpi = move_data.rev_lookup.find(rhs_lval); - let state = sets.on_entry.get_bit(rhs_mpi.idx()); - debug!("rustc_peek: propagate into lvalue {:?} ({:?}) from rhs: {:?} state: {}", - lvalue, lhs_mpi, rhs_lval, state); - if state { - sets.on_entry.set_bit(lhs_mpi.idx()); - } else { - sets.on_entry.clear_bit(lhs_mpi.idx()); - } - } else { - debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}", - lvalue, lhs_mpi, stmt); - // reset GEN and KILL sets before emulating their effect. - for e in &mut sets.gen_set[..] { *e = 0; } - for e in &mut sets.kill_set[..] { *e = 0; } - results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j); - bitwise(sets.on_entry, sets.gen_set, &Union); - bitwise(sets.on_entry, sets.kill_set, &Subtract); - } + debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}", + lvalue, lhs_mpi, stmt); + // reset GEN and KILL sets before emulating their effect. + for e in &mut sets.gen_set[..] { *e = 0; } + for e in &mut sets.kill_set[..] { *e = 0; } + results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j); + bitwise(sets.on_entry, sets.gen_set, &Union); + bitwise(sets.on_entry, sets.kill_set, &Subtract); } tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ From bdcf6795f7ccf5006cc486515af25491255258f1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 May 2016 20:19:07 -0400 Subject: [PATCH 025/179] always make at least one codegen-unit this allows us to remove the dummy `foo` fn --- src/librustc_trans/partitioning.rs | 11 +++++++++++ .../incremental/type_alias_cross_crate/auxiliary/a.rs | 2 -- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 098ba759247b..d2ddbccee8b4 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -228,6 +228,17 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // always ensure we have at least one CGO; otherwise, if we have a + // crate with just types (for example), we could wind up with no CGU + if codegen_units.is_empty() { + let codegen_unit_name = InternedString::new(FALLBACK_CODEGEN_UNIT); + codegen_units.entry(codegen_unit_name.clone()) + .or_insert_with(|| CodegenUnit { + name: codegen_unit_name.clone(), + items: FnvHashMap(), + }); + } + PreInliningPartitioning { codegen_units: codegen_units.into_iter() .map(|(_, codegen_unit)| codegen_unit) diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs index 2494dca0509b..446d97e5bc05 100644 --- a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs @@ -17,5 +17,3 @@ pub type X = u32; pub type X = i32; pub type Y = char; - -pub fn foo() { } From 0e9d8192cae3ff5812a204a2287edf4c4a71a623 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 19 May 2016 05:22:42 +0000 Subject: [PATCH 026/179] Allow `concat_idents!` in type positions as well as in expression positions --- src/libsyntax_ext/concat_idents.rs | 50 ++++++++++++------- .../compile-fail/syntax-extension-minor.rs | 9 ++-- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index dce808756cf6..3d5f32eadb3c 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -52,22 +52,36 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) } let res = str_to_ident(&res_str); - let e = P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Path(None, - ast::Path { - span: sp, - global: false, - segments: vec!( - ast::PathSegment { - identifier: res, - parameters: ast::PathParameters::none(), - } - ) - } - ), - span: sp, - attrs: None, - }); - MacEager::expr(e) + struct Result { ident: ast::Ident, span: Span }; + + impl Result { + fn path(&self) -> ast::Path { + let segment = ast::PathSegment { + identifier: self.ident, + parameters: ast::PathParameters::none() + }; + ast::Path { span: self.span, global: false, segments: vec![segment] } + } + } + + impl base::MacResult for Result { + fn make_expr(self: Box) -> Option> { + Some(P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprKind::Path(None, self.path()), + span: self.span, + attrs: None, + })) + } + + fn make_ty(self: Box) -> Option> { + Some(P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Path(None, self.path()), + span: self.span, + })) + } + } + + Box::new(Result { ident: res, span: sp }) } diff --git a/src/test/compile-fail/syntax-extension-minor.rs b/src/test/compile-fail/syntax-extension-minor.rs index 38a6834a9c46..3e36b126523a 100644 --- a/src/test/compile-fail/syntax-extension-minor.rs +++ b/src/test/compile-fail/syntax-extension-minor.rs @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// this now fails (correctly, I claim) because hygiene prevents -// the assembled identifier from being a reference to the binding. -#![feature(concat_idents)] +#![feature(concat_idents, type_macros)] pub fn main() { + struct Foo; + let _: concat_idents!(F, oo) = Foo; // Test that `concat_idents!` can be used in type positions + let asdf_fdsa = "<.<".to_string(); + // this now fails (correctly, I claim) because hygiene prevents + // the assembled identifier from being a reference to the binding. assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string()); //~^ ERROR: unresolved name `asdf_fdsa` From 144c1334aa95c6557ce603fdb5e7ce6353f5d861 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 19 May 2016 22:35:09 -0700 Subject: [PATCH 027/179] Mention that the panic hook will always run --- src/libstd/panic.rs | 2 +- src/libstd/panicking.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index a2c6e79fb92f..3b170dc9c6d5 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -395,7 +395,7 @@ pub fn recover R + UnwindSafe, R>(f: F) -> Result { catch_unwind(f) } -/// Triggers a panic without invoking the panic handler. +/// Triggers a panic without invoking the panic hook. /// /// This is designed to be used in conjunction with `catch_unwind` to, for /// example, carry a panic across a layer of C code. diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index b85d4b330a6e..3ad330e79fa2 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -75,10 +75,11 @@ static FIRST_PANIC: AtomicBool = AtomicBool::new(true); /// Registers a custom panic hook, replacing any that was previously registered. /// -/// The panic hook is invoked when a thread panics, but before it begins -/// unwinding the stack. The default hook prints a message to standard error -/// and generates a backtrace if requested, but this behavior can be customized -/// with the `set_hook` and `take_hook` functions. +/// The panic hook is invoked when a thread panics, but before the panic runtime +/// is invoked. As such, the hook will run with both the aborting and unwinding +/// runtimes. The default hook prints a message to standard error and generates +/// a backtrace if requested, but this behavior can be customized with the +/// `set_hook` and `take_hook` functions. /// /// The hook is provided with a `PanicInfo` struct which contains information /// about the origin of the panic, including the payload passed to `panic!` and From 43924978efa4e0fa062cfab73a45cc27a9708023 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 13:12:02 +0200 Subject: [PATCH 028/179] markdown fix suggested during review. --- src/test/compile-fail/mir-dataflow/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/mir-dataflow/README.md b/src/test/compile-fail/mir-dataflow/README.md index eaf2cf7f8059..a3ab14b23c7d 100644 --- a/src/test/compile-fail/mir-dataflow/README.md +++ b/src/test/compile-fail/mir-dataflow/README.md @@ -12,7 +12,7 @@ error is emitted by the compiler at that point; if it is a 0-bit, then that invocation of `rustc_peek` will emit an error with the message "rustc_peek: bit not set". -(*): Or `#[rustc_mir(rustc_peek_maybe_uninit)]`, and perhaps other +(\*): Or `#[rustc_mir(rustc_peek_maybe_uninit)]`, and perhaps other variants in the future. The end effect is that one can write unit tests for MIR dataflow that From a0db1346efcc15ee884a1dc7d1787bd0b6869be0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 13:18:03 +0200 Subject: [PATCH 029/179] `mir::dataflow::sanity_check`: Factor out `fn is_rustc_peek` helper routine. --- .../borrowck/mir/dataflow/sanity_check.rs | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index b45b79229128..7c8a9a4aeb0f 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -10,6 +10,7 @@ use syntax::abi::{Abi}; use syntax::ast; +use syntax::codemap::Span; use rustc::ty::{self, TyCtxt}; use rustc::mir::repr::{self, Mir}; @@ -58,34 +59,9 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ref terminator, is_cleanup: _ } = bb_data; - let (args, span) = if let Some(repr::Terminator { ref kind, span, .. }) = *terminator { - if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind - { - if let repr::Operand::Constant(ref func) = *oper - { - if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty - { - let name = tcx.item_name(def_id); - if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - if name.as_str() == "rustc_peek" { - (args, span) - } else { - continue; - } - } else { - continue; - } - } else { - continue; - } - } else { - continue; - } - } else { - continue; - } - } else { - continue; + let (args, span) = match is_rustc_peek(tcx, terminator) { + Some(args_and_span) => args_and_span, + None => continue, }; assert!(args.len() == 1); let peek_arg_lval = match args[0] { @@ -162,4 +138,28 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, rustc_peek expects input of \ form `&expr`")); } + +} + +fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + terminator: &'a Option>) + -> Option<(&'a [repr::Operand<'tcx>], Span)> { + if let Some(repr::Terminator { ref kind, span, .. }) = *terminator { + if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind + { + if let repr::Operand::Constant(ref func) = *oper + { + if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty + { + let name = tcx.item_name(def_id); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + if name.as_str() == "rustc_peek" { + return Some((args, span)); + } + } + } + } + } + } + return None; } From 743518bc214fbeddcdb89ce20626cacae5404e21 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 13:18:27 +0200 Subject: [PATCH 030/179] fix comment in `impl DataflowOperator for MaybeUninitializedLvals`. --- src/librustc_borrowck/borrowck/mir/dataflow/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 4cf739396e7f..9f0186a36a83 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -1132,7 +1132,7 @@ impl<'a, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> { #[inline] fn initial_value() -> bool { - false // bottom = uninitialized + false // bottom = initialized (start_block_effect counters this at outset) } } From 7eb5e045948964c7227488d30910df0bdc1a099f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 13:20:00 +0200 Subject: [PATCH 031/179] `borrowck::mir`: alpha-renamed DropFlagState variant names. --- .../borrowck/mir/dataflow/mod.rs | 18 +++++++++--------- src/librustc_borrowck/borrowck/mir/mod.rs | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 9f0186a36a83..cb110e606f22 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -827,11 +827,11 @@ impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { state: super::DropFlagState) { match state { - DropFlagState::Dead => { + DropFlagState::Absent => { sets.gen_set.clear_bit(path.idx()); sets.kill_set.set_bit(path.idx()); } - DropFlagState::Live => { + DropFlagState::Present => { sets.gen_set.set_bit(path.idx()); sets.kill_set.clear_bit(path.idx()); } @@ -844,11 +844,11 @@ impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { state: super::DropFlagState) { match state { - DropFlagState::Dead => { + DropFlagState::Absent => { sets.gen_set.set_bit(path.idx()); sets.kill_set.clear_bit(path.idx()); } - DropFlagState::Live => { + DropFlagState::Present => { sets.gen_set.clear_bit(path.idx()); sets.kill_set.set_bit(path.idx()); } @@ -861,11 +861,11 @@ impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { state: super::DropFlagState) { match state { - DropFlagState::Dead => { + DropFlagState::Absent => { sets.gen_set.clear_bit(path.idx()); sets.kill_set.set_bit(path.idx()); } - DropFlagState::Live => { + DropFlagState::Present => { sets.gen_set.set_bit(path.idx()); sets.kill_set.clear_bit(path.idx()); } @@ -889,7 +889,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { super::drop_flag_effects_for_function_entry( ctxt.0, ctxt.1, &ctxt.2, |path, s| { - assert!(s == DropFlagState::Live); + assert!(s == DropFlagState::Present); sets.on_entry.set_bit(path.idx()); }); } @@ -956,7 +956,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { super::drop_flag_effects_for_function_entry( ctxt.0, ctxt.1, &ctxt.2, |path, s| { - assert!(s == DropFlagState::Live); + assert!(s == DropFlagState::Present); sets.on_entry.clear_bit(path.idx()); }); } @@ -1022,7 +1022,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { super::drop_flag_effects_for_function_entry( ctxt.0, ctxt.1, &ctxt.2, |path, s| { - assert!(s == DropFlagState::Live); + assert!(s == DropFlagState::Present); sets.on_entry.set_bit(path.idx()); }); } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 405647aec026..a3cf6176779c 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -195,8 +195,8 @@ impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { #[derive(Debug, PartialEq, Eq, Copy, Clone)] enum DropFlagState { - Live, - Dead + Present, // i.e. initialized + Absent, // i.e. deinitialized or "moved" } fn on_all_children_bits<'a, 'tcx, F>( @@ -266,7 +266,7 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( let move_path_index = move_data.rev_lookup.find(&lvalue); on_all_children_bits(tcx, mir, move_data, move_path_index, - |moi| callback(moi, DropFlagState::Live)); + |moi| callback(moi, DropFlagState::Present)); } } @@ -296,7 +296,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( on_all_children_bits(tcx, mir, move_data, path, - |moi| callback(moi, DropFlagState::Dead)) + |moi| callback(moi, DropFlagState::Absent)) } let bb = mir.basic_block_data(loc.block); @@ -306,7 +306,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( debug!("drop_flag_effects: assignment {:?}", stmt); on_all_children_bits(tcx, mir, move_data, move_data.rev_lookup.find(lvalue), - |moi| callback(moi, DropFlagState::Live)) + |moi| callback(moi, DropFlagState::Present)) } }, None => { From 4ea5b790d918f167819c74dd9e9361beca2d6578 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 13:20:33 +0200 Subject: [PATCH 032/179] Added comment pointing out somewhat subtle initialization in `fn start_block_effect`. --- src/librustc_borrowck/borrowck/mir/dataflow/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index cb110e606f22..4bc5a5409ece 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -951,6 +951,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { // sets on_entry bits for Arg lvalues fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { + // set all bits to 1 (uninit) before gathering counterevidence for e in &mut sets.on_entry[..] { *e = !0; } super::drop_flag_effects_for_function_entry( From 6ad8b3cb60db9464b4e86b3c87c59529fd53ca47 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 13:40:52 +0200 Subject: [PATCH 033/179] `mir::dataflow` arielb1 review feedback * removed `on_all_children_bits`, rewriting calls to use `super::on_all_children_bits` * moved `fn path` helper routine out of `impl MirBorrowckCtxtPreDataflow` --- .../borrowck/mir/dataflow/mod.rs | 96 +++++++------------ 1 file changed, 32 insertions(+), 64 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 4bc5a5409ece..8c3a843e4647 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -19,7 +19,7 @@ use std::path::PathBuf; use std::usize; use super::MirBorrowckCtxtPreDataflow; -use super::gather_moves::{Location, MoveData, MovePathData, MovePathIndex, MoveOutIndex, PathMap}; +use super::gather_moves::{Location, MoveData, MovePathIndex, MoveOutIndex}; use super::gather_moves::{MoveOut, MovePath}; use super::DropFlagState; @@ -99,40 +99,6 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> } } -fn on_all_children_bits(path_map: &PathMap, - move_paths: &MovePathData, - move_path_index: MovePathIndex, - mut each_child: Each) - where Each: FnMut(MoveOutIndex) -{ - return on_all_children_bits_recur( - path_map, move_paths, move_path_index, &mut each_child); - - fn on_all_children_bits_recur(path_map: &PathMap, - move_paths: &MovePathData, - move_path_index: MovePathIndex, - each_child: &mut Each) - where Each: FnMut(MoveOutIndex) - { - // 1. invoke `each_child` callback for all moves that directly - // influence path for `move_path_index` - for move_index in &path_map[move_path_index] { - each_child(*move_index); - } - - // 2. for each child of the path (that is named in this - // function), recur. - // - // (Unnamed children are irrelevant to dataflow; by - // definition they have no associated moves.) - let mut next_child_index = move_paths[move_path_index].first_child; - while let Some(child_index) = next_child_index { - on_all_children_bits_recur(path_map, move_paths, child_index, each_child); - next_child_index = move_paths[child_index].next_sibling; - } - } -} - impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> { @@ -161,23 +127,23 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> } } +fn dataflow_path(context: &str, prepost: &str, path: &str) -> PathBuf { + format!("{}_{}", context, prepost); + let mut path = PathBuf::from(path); + let new_file_name = { + let orig_file_name = path.file_name().unwrap().to_str().unwrap(); + format!("{}_{}", context, orig_file_name) + }; + path.set_file_name(new_file_name); + path +} + impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> { - fn path(context: &str, prepost: &str, path: &str) -> PathBuf { - format!("{}_{}", context, prepost); - let mut path = PathBuf::from(path); - let new_file_name = { - let orig_file_name = path.file_name().unwrap().to_str().unwrap(); - format!("{}_{}", context, orig_file_name) - }; - path.set_file_name(new_file_name); - path - } - fn pre_dataflow_instrumentation(&self) -> io::Result<()> { if let Some(ref path_str) = self.print_preflow_to { - let path = Self::path(BD::name(), "preflow", path_str); + let path = dataflow_path(BD::name(), "preflow", path_str); graphviz::print_borrowck_graph_to(self, &path) } else { Ok(()) @@ -186,7 +152,7 @@ impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> fn post_dataflow_instrumentation(&self) -> io::Result<()> { if let Some(ref path_str) = self.print_postflow_to { - let path = Self::path(BD::name(), "postflow", path_str); + let path = dataflow_path(BD::name(), "postflow", path_str); graphviz::print_borrowck_graph_to(self, &path) } else{ Ok(()) @@ -746,9 +712,8 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { sets: &mut BlockSets, bb: repr::BasicBlock, idx: usize) { - let &(_tcx, mir, ref move_data) = ctxt; + let &(tcx, mir, ref move_data) = ctxt; let stmt = &mir.basic_block_data(bb).statements[idx]; - let move_paths = &move_data.move_paths; let loc_map = &move_data.loc_map; let path_map = &move_data.path_map; let rev_lookup = &move_data.rev_lookup; @@ -771,13 +736,14 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let move_path_index = rev_lookup.find(lvalue); sets.kill_set.set_bit(move_path_index.idx()); - on_all_children_bits(path_map, - move_paths, - move_path_index, - |moi| { - assert!(moi.idx() < bits_per_block); - sets.kill_set.set_bit(moi.idx()); - }); + super::on_all_children_bits(tcx, + mir, + move_data, + move_path_index, + |mpi| for moi in &path_map[mpi] { + assert!(moi.idx() < bits_per_block); + sets.kill_set.set_bit(moi.idx()); + }); } } } @@ -812,13 +778,15 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let bits_per_block = self.bits_per_block(ctxt); in_out.clear_bit(move_path_index.idx()); - on_all_children_bits(&move_data.path_map, - &move_data.move_paths, - move_path_index, - |moi| { - assert!(moi.idx() < bits_per_block); - in_out.clear_bit(moi.idx()); - }); + let path_map = &move_data.path_map; + super::on_all_children_bits(ctxt.0, + ctxt.1, + move_data, + move_path_index, + |mpi| for moi in &path_map[mpi] { + assert!(moi.idx() < bits_per_block); + in_out.clear_bit(moi.idx()); + }); } } From 3ebaf457535ae8bff392a0d86fd4ffeca45a2b76 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 14:14:18 +0200 Subject: [PATCH 034/179] Review feedback. Removed `BitDenotation: DataflowOperator` relationship. Alpha-renamed `fn initial_value` to `fn bottom_value`. --- .../borrowck/mir/dataflow/mod.rs | 41 +++++++++---------- src/librustc_borrowck/borrowck/mir/mod.rs | 3 +- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 8c3a843e4647..00589e05ffd3 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -35,7 +35,7 @@ pub trait Dataflow { } impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation + DataflowOperator, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> { fn dataflow(&mut self) { self.flow_state.build_sets(); @@ -53,7 +53,7 @@ struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> } impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> - where BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx> { fn propagate(&mut self) { let mut temp = vec![0; self.flow_state.sets.words_per_block]; @@ -100,10 +100,10 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> } impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> - where BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx> { fn reset(&mut self, bits: &mut [usize]) { - let e = if BD::initial_value() {usize::MAX} else {0}; + let e = if BD::bottom_value() {usize::MAX} else {0}; for b in bits { *b = e; } @@ -317,17 +317,17 @@ impl DataflowState { } pub trait BitwiseOperator { - /// Joins two predecessor bits together, typically either `|` or `&` + /// Applies some bit-operation pointwise to each of the bits in the two inputs. fn join(&self, pred1: usize, pred2: usize) -> usize; } /// Parameterization for the precise form of data flow that is used. -pub trait DataflowOperator : BitwiseOperator { +pub trait DataflowOperator: BitwiseOperator { /// Specifies the initial value for each bit in the `on_entry` set - fn initial_value() -> bool; + fn bottom_value() -> bool; } -pub trait BitDenotation: DataflowOperator { +pub trait BitDenotation { /// Specifies what is represented by each bit in the dataflow bitvector. type Bit; @@ -425,7 +425,7 @@ pub trait BitDenotation: DataflowOperator { } impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> - where D: BitDenotation, D::Ctxt: HasMoveData<'tcx> + where D: BitDenotation + DataflowOperator, D::Ctxt: HasMoveData<'tcx> { pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, @@ -437,7 +437,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> let num_blocks = mir.basic_blocks.len(); let num_words = num_blocks * words_per_block; - let entry = if D::initial_value() { usize::MAX } else {0}; + let entry = if D::bottom_value() { usize::MAX } else {0}; let zeroes = Bits::new(0, num_words); let on_entry = Bits::new(entry, num_words); @@ -460,7 +460,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> } impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> - where D: BitDenotation, D::Ctxt: HasMoveData<'tcx> + where D: BitDenotation + DataflowOperator, D::Ctxt: HasMoveData<'tcx> { /// Propagates the bits of `in_out` into all the successors of `bb`, /// using bitwise operator denoted by `self.operator`. @@ -851,7 +851,6 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { &ctxt.2.move_paths[MovePathIndex::new(idx)] } - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { super::drop_flag_effects_for_function_entry( @@ -1072,12 +1071,10 @@ impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> { } } -// FIXME: `DataflowOperator::initial_value` should be named -// `bottom_value`. The way that dataflow fixed point iteration works, -// you want to start at bottom and work your way to a fixed point. -// This needs to include the detail that the control-flow merges will -// apply the `join` operator above to current state (which starts at -// that bottom value). +// The way that dataflow fixed point iteration works, you want to +// start at bottom and work your way to a fixed point. Control-flow +// merges will apply the `join` operator to each block entry's current +// state (which starts at that bottom value). // // This means, for propagation across the graph, that you either want // to start at all-zeroes and then use Union as your merge when @@ -1086,28 +1083,28 @@ impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> DataflowOperator for MovingOutStatements<'a, 'tcx> { #[inline] - fn initial_value() -> bool { + fn bottom_value() -> bool { false // bottom = no loans in scope by default } } impl<'a, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'tcx> { #[inline] - fn initial_value() -> bool { + fn bottom_value() -> bool { false // bottom = uninitialized } } impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> { #[inline] - fn initial_value() -> bool { + fn bottom_value() -> bool { false // bottom = initialized (start_block_effect counters this at outset) } } impl<'a, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'tcx> { #[inline] - fn initial_value() -> bool { + fn bottom_value() -> bool { true // bottom = initialized } } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index a3cf6176779c..37c042844e58 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -29,6 +29,7 @@ mod gather_moves; // mod graphviz; use self::dataflow::{BitDenotation}; +use self::dataflow::{DataflowOperator}; use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; use self::dataflow::{HasMoveData}; use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; @@ -119,7 +120,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, attributes: &[ast::Attribute], ctxt: BD::Ctxt, bd: BD) -> (BD::Ctxt, DataflowResults) - where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation + DataflowOperator, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> { use syntax::attr::AttrMetaMethods; From 2d0b931b6ddadb599e084549043039a3e70f7939 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 15:44:30 +0200 Subject: [PATCH 035/179] review feedback: fix some index-mismatch bugs pointed out by arielb1. --- src/librustc_borrowck/borrowck/mir/dataflow/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 00589e05ffd3..09abbb6af681 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -734,8 +734,6 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { // MoveOuts from it, and *also* all MoveOuts // for children and associated fragment sets. let move_path_index = rev_lookup.find(lvalue); - - sets.kill_set.set_bit(move_path_index.idx()); super::on_all_children_bits(tcx, mir, move_data, @@ -777,7 +775,6 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let move_path_index = move_data.rev_lookup.find(dest_lval); let bits_per_block = self.bits_per_block(ctxt); - in_out.clear_bit(move_path_index.idx()); let path_map = &move_data.path_map; super::on_all_children_bits(ctxt.0, ctxt.1, From 5531a6374cf5d34ba1f02210a9528742d59de7a5 Mon Sep 17 00:00:00 2001 From: Aaklo Xu Date: Fri, 20 May 2016 21:55:19 +0800 Subject: [PATCH 036/179] Fix references links There are Duplicate link references in the article and the format is incorrect. --- src/doc/book/primitive-types.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/doc/book/primitive-types.md b/src/doc/book/primitive-types.md index 2a4b7ba37f25..330e3bf6a61c 100644 --- a/src/doc/book/primitive-types.md +++ b/src/doc/book/primitive-types.md @@ -171,12 +171,10 @@ and a length. ## Slicing syntax You can use a combo of `&` and `[]` to create a slice from various things. The -`&` indicates that slices are similar to [references], which we will cover in +`&` indicates that slices are similar to [references][references], which we will cover in detail later in this section. The `[]`s, with a range, let you define the length of the slice: -[references]: references-and-borrowing.html - ```rust let a = [0, 1, 2, 3, 4]; let complete = &a[..]; // A slice containing all of the elements in a @@ -198,7 +196,7 @@ documentation][slice]. Rust’s `str` type is the most primitive string type. As an [unsized type][dst], it’s not very useful by itself, but becomes useful when placed behind a reference, like `&str`. We'll elaborate further when we cover -[Strings][strings] and [references]. +[Strings][strings] and [references][references]. [dst]: unsized-types.html [strings]: strings.html From 2c2eb71f6baddea8b203d6e7ebbcdf12348ea5c5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 May 2016 17:40:22 +0200 Subject: [PATCH 037/179] Refactor `bitslice`: distinguish `usize` for indexing vs word type being indexed. --- src/librustc_borrowck/bitslice.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_borrowck/bitslice.rs index ca672e808843..1c01e98cf859 100644 --- a/src/librustc_borrowck/bitslice.rs +++ b/src/librustc_borrowck/bitslice.rs @@ -10,7 +10,9 @@ use std::mem; -/// `BitSlice` provides helper methods for treating a `[usize]` +pub type Word = usize; + +/// `BitSlice` provides helper methods for treating a `[Word]` /// as a bitvector. pub trait BitSlice { fn clear_bit(&mut self, idx: usize) -> bool; @@ -18,12 +20,12 @@ pub trait BitSlice { fn get_bit(&self, idx: usize) -> bool; } -impl BitSlice for [usize] { +impl BitSlice for [Word] { /// Clears bit at `idx` to 0; returns true iff this changed `self.` fn clear_bit(&mut self, idx: usize) -> bool { let words = self; debug!("clear_bit: words={} idx={}", - bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); + bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx); debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask); let oldv = words[word]; @@ -36,7 +38,7 @@ impl BitSlice for [usize] { fn set_bit(&mut self, idx: usize) -> bool { let words = self; debug!("set_bit: words={} idx={}", - bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); + bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx); debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask); let oldv = words[word]; @@ -54,31 +56,31 @@ impl BitSlice for [usize] { } struct BitLookup { - /// An index of the word holding the bit in original `[usize]` of query. + /// An index of the word holding the bit in original `[Word]` of query. word: usize, /// Index of the particular bit within the word holding the bit. bit_in_word: usize, /// Word with single 1-bit set corresponding to where the bit is located. - bit_mask: usize, + bit_mask: Word, } #[inline] fn bit_lookup(bit: usize) -> BitLookup { - let usize_bits = mem::size_of::() * 8; - let word = bit / usize_bits; - let bit_in_word = bit % usize_bits; + let word_bits = mem::size_of::() * 8; + let word = bit / word_bits; + let bit_in_word = bit % word_bits; let bit_mask = 1 << bit_in_word; BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask } } -fn bit_str(bit: usize) -> String { +fn bit_str(bit: Word) -> String { let byte = bit >> 3; let lobits = 1 << (bit & 0b111); format!("[{}:{}-{:02x}]", bit, byte, lobits) } -pub fn bits_to_string(words: &[usize], bits: usize) -> String { +pub fn bits_to_string(words: &[Word], bits: usize) -> String { let mut result = String::new(); let mut sep = '['; From 0e4c9c2f1a263fc88b05fe8f1e940e2d0dcc3365 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Fri, 20 May 2016 19:21:35 -0700 Subject: [PATCH 038/179] Added a `rustdoc` shortcut for collapse/expand all Now when the user presses the "+" key all sections will collapse/expand. Also added a note to the help screen which describes this behavior. --- src/librustdoc/html/layout.rs | 2 ++ src/librustdoc/html/static/main.js | 10 ++++++++-- src/librustdoc/html/static/rustdoc.css | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index a168fe98a94c..265ed6be1552 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -103,6 +103,8 @@ r##"
Move down in search results
Go to active search result
+
+
+
Collapse/expand all sections
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index a368b4197a39..0ec5cab78bc7 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -124,6 +124,10 @@ focusSearchBar(); break; + case "+": + toggleAllDocs(); + break; + case "?": if (ev.shiftKey && $("#help").hasClass("hidden")) { ev.preventDefault(); @@ -931,7 +935,7 @@ return "\u2212"; // "\u2212" is '−' minus sign } - $("#toggle-all-docs").on("click", function() { + function toggleAllDocs() { var toggle = $("#toggle-all-docs"); if (toggle.hasClass("will-expand")) { toggle.removeClass("will-expand"); @@ -950,7 +954,9 @@ $(".toggle-wrapper").addClass("collapsed"); $(".collapse-toggle").children(".inner").text(labelForToggleButton(true)); } - }); + } + + $("#toggle-all-docs").on("click", toggleAllDocs); $(document).on("click", ".collapse-toggle", function() { var toggle = $(this); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index a52a914fea68..8e4245d4ebf1 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -472,7 +472,7 @@ body.blur > :not(#help) { background: #e9e9e9; box-shadow: 0 0 6px rgba(0,0,0,.2); width: 550px; - height: 300px; + height: 330px; border: 1px solid #bfbfbf; } #help dt { From 540c69fa4dc0a0d5e73fc68533fea9c4e5e5b3e1 Mon Sep 17 00:00:00 2001 From: Aaklo Xu Date: Sat, 21 May 2016 14:40:57 +0800 Subject: [PATCH 039/179] src/doc: Keep the original style of links --- src/doc/book/primitive-types.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/primitive-types.md b/src/doc/book/primitive-types.md index 330e3bf6a61c..b6a123bb3674 100644 --- a/src/doc/book/primitive-types.md +++ b/src/doc/book/primitive-types.md @@ -171,7 +171,7 @@ and a length. ## Slicing syntax You can use a combo of `&` and `[]` to create a slice from various things. The -`&` indicates that slices are similar to [references][references], which we will cover in +`&` indicates that slices are similar to [references], which we will cover in detail later in this section. The `[]`s, with a range, let you define the length of the slice: @@ -196,7 +196,7 @@ documentation][slice]. Rust’s `str` type is the most primitive string type. As an [unsized type][dst], it’s not very useful by itself, but becomes useful when placed behind a reference, like `&str`. We'll elaborate further when we cover -[Strings][strings] and [references][references]. +[Strings][strings] and [references]. [dst]: unsized-types.html [strings]: strings.html From afa39058f6444967d1dc336ae513cfe23c0ed55d Mon Sep 17 00:00:00 2001 From: Ticki Date: Mon, 21 Dec 2015 22:24:15 +0100 Subject: [PATCH 040/179] Improve internal documentation and code style Fix some code layout, remove some unnecessary returns, fix typos, punctuation, and comment consistency. --- src/librustc/hir/map/blocks.rs | 8 +++++- src/librustc/hir/map/collector.rs | 5 +++- src/librustc/hir/map/definitions.rs | 29 ++++++++++++++++---- src/librustc_back/sha2.rs | 41 +++++++++++++---------------- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 4af37fe16adb..bac96c68e4cf 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -133,7 +133,13 @@ struct ClosureParts<'a> { impl<'a> ClosureParts<'a> { fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self { - ClosureParts { decl: d, body: b, id: id, span: s, attrs: attrs } + ClosureParts { + decl: d, + body: b, + id: id, + span: s, + attrs: attrs, + } } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 9f55f46541cf..99e5f32e263f 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -19,10 +19,13 @@ use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID}; use syntax::codemap::Span; -/// A Visitor that walks over the HIR and collects Node's into a HIR map. +/// A Visitor that walks over the HIR and collects Nodes into a HIR map pub struct NodeCollector<'ast> { + /// The crate pub krate: &'ast Crate, + /// The node map pub map: Vec>, + /// The parent of this node pub parent_node: NodeId, } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 457511cdbc3b..d66df3e4e8fd 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -15,6 +15,7 @@ use syntax::ast; use syntax::parse::token::InternedString; use util::nodemap::NodeMap; +/// The definition table containing node definitions #[derive(Clone)] pub struct Definitions { data: Vec, @@ -139,31 +140,47 @@ pub struct InlinedRootPath { pub enum DefPathData { // Root: these should only be used for the root nodes, because // they are treated specially by the `def_path` function. + /// The crate root (marker) CrateRoot, + /// An inlined root InlinedRoot(Box), // Catch-all for random DefId things like DUMMY_NODE_ID Misc, // Different kinds of items and item-like things: + /// An impl Impl, - TypeNs(ast::Name), // something in the type NS - ValueNs(ast::Name), // something in the value NS + /// Something in the type NS + TypeNs(ast::Name), + /// Something in the value NS + ValueNs(ast::Name), + /// A module declaration Module(ast::Name), + /// A macro rule MacroDef(ast::Name), + /// A closure expression ClosureExpr, // Subportions of items + /// A type parameter (generic parameter) TypeParam(ast::Name), + /// A lifetime definition LifetimeDef(ast::Name), + /// A variant of a enum EnumVariant(ast::Name), + /// A struct field Field(ast::Name), - StructCtor, // implicit ctor for a tuple-like struct - Initializer, // initializer for a const - Binding(ast::Name), // pattern binding + /// Implicit ctor for a tuple-like struct + StructCtor, + /// Initializer for a const + Initializer, + /// Pattern binding + Binding(ast::Name), } impl Definitions { + /// Create new empty definition map. pub fn new() -> Definitions { Definitions { data: vec![], @@ -172,6 +189,7 @@ impl Definitions { } } + /// Get the number of definitions. pub fn len(&self) -> usize { self.data.len() } @@ -214,6 +232,7 @@ impl Definitions { } } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, parent: Option, node_id: ast::NodeId, diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index 404298d8839a..97fb39c17ea0 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -25,11 +25,10 @@ fn write_u32_be(dst: &mut[u8], input: u32) { /// Read the value of a vector of bytes as a u32 value in big-endian format. fn read_u32_be(input: &[u8]) -> u32 { - return - (input[0] as u32) << 24 | + (input[0] as u32) << 24 | (input[1] as u32) << 16 | (input[2] as u32) << 8 | - (input[3] as u32); + (input[3] as u32) } /// Read a vector of bytes into a vector of u32s. The values are read in big-endian format. @@ -50,7 +49,7 @@ trait ToBits: Sized { impl ToBits for u64 { fn to_bits(self) -> (u64, u64) { - return (self >> 61, self << 3); + (self >> 61, self << 3) } } @@ -64,7 +63,7 @@ fn add_bytes_to_bits(bits: u64, bytes: u64) -> u64 { } match bits.checked_add(new_low_bits) { - Some(x) => return x, + Some(x) => x, None => panic!("numeric overflow occurred.") } } @@ -113,10 +112,10 @@ struct FixedBuffer64 { impl FixedBuffer64 { /// Create a new FixedBuffer64 fn new() -> FixedBuffer64 { - return FixedBuffer64 { + FixedBuffer64 { buffer: [0; 64], buffer_idx: 0 - }; + } } } @@ -175,13 +174,13 @@ impl FixedBuffer for FixedBuffer64 { fn next<'s>(&'s mut self, len: usize) -> &'s mut [u8] { self.buffer_idx += len; - return &mut self.buffer[self.buffer_idx - len..self.buffer_idx]; + &mut self.buffer[self.buffer_idx - len..self.buffer_idx] } fn full_buffer<'s>(&'s mut self) -> &'s [u8] { assert!(self.buffer_idx == 64); self.buffer_idx = 0; - return &self.buffer[..64]; + &self.buffer[..64] } fn position(&self) -> usize { self.buffer_idx } @@ -278,7 +277,7 @@ struct Engine256State { impl Engine256State { fn new(h: &[u32; 8]) -> Engine256State { - return Engine256State { + Engine256State { h0: h[0], h1: h[1], h2: h[2], @@ -287,7 +286,7 @@ impl Engine256State { h5: h[5], h6: h[6], h7: h[7] - }; + } } fn reset(&mut self, h: &[u32; 8]) { @@ -433,7 +432,7 @@ struct Engine256 { impl Engine256 { fn new(h: &[u32; 8]) -> Engine256 { - return Engine256 { + Engine256 { length_bits: 0, buffer: FixedBuffer64::new(), state: Engine256State::new(h), @@ -457,17 +456,15 @@ impl Engine256 { } fn finish(&mut self) { - if self.finished { - return; + if !self.finished { + let self_state = &mut self.state; + self.buffer.standard_padding(8, |input: &[u8]| { self_state.process_block(input) }); + write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 ); + write_u32_be(self.buffer.next(4), self.length_bits as u32); + self_state.process_block(self.buffer.full_buffer()); + + self.finished = true; } - - let self_state = &mut self.state; - self.buffer.standard_padding(8, |input: &[u8]| { self_state.process_block(input) }); - write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 ); - write_u32_be(self.buffer.next(4), self.length_bits as u32); - self_state.process_block(self.buffer.full_buffer()); - - self.finished = true; } } From eb54041ac73d548344cb9eac97b898494e644785 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 19 May 2016 09:45:37 +0000 Subject: [PATCH 041/179] Introduce `MacroGenerable` trait --- src/libsyntax/ext/expand.rs | 99 +++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f243706eecb8..b2ebe0e0145f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -35,6 +35,40 @@ use std_inject; use std::collections::HashSet; use std::env; +trait MacroGenerable: Sized { + fn make_with<'a>(result: Box) -> Option; + fn fold_with(self, folder: &mut F) -> Self; + fn dummy(span: Span) -> Self; + fn kind_name() -> &'static str; +} + +macro_rules! impl_macro_generable { + ($($ty:ty: $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*, + |$span:ident| $dummy:expr;)*) => { $( + impl MacroGenerable for $ty { + fn kind_name() -> &'static str { $kind_name } + fn make_with<'a>(result: Box) -> Option { result.$make() } + fn fold_with(self, folder: &mut F) -> Self { + $( folder.$fold(self) )* + $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )* + } + fn dummy($span: Span) -> Self { $dummy } + } + )* } +} + +impl_macro_generable! { + P: "expression", .make_expr, .fold_expr, |span| DummyResult::raw_expr(span); + P: "pattern", .make_pat, .fold_pat, |span| P(DummyResult::raw_pat(span)); + P: "type", .make_ty, .fold_ty, |span| DummyResult::raw_ty(span); + SmallVector: + "impl item", .make_impl_items, lift .fold_impl_item, |_span| SmallVector::zero(); + SmallVector>: + "item", .make_items, lift .fold_item, |_span| SmallVector::zero(); + SmallVector: + "statement", .make_stmts, lift .fold_stmt, |_span| SmallVector::zero(); +} + // this function is called to detect use of feature-gated or invalid attributes // on macro invoations since they will not be detected after macro expansion fn check_attributes(attrs: &[ast::Attribute], fld: &MacroExpander) { @@ -59,9 +93,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // Assert that we drop any macro attributes on the floor here drop(attrs); - let expanded_expr = match expand_mac_invoc(mac, span, - |r| r.make_expr(), - mark_expr, fld) { + let expanded_expr = match expand_mac_invoc(mac, span, fld) { Some(expr) => expr, None => { return DummyResult::raw_expr(span); @@ -182,19 +214,9 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }); } -/// Expand a (not-ident-style) macro invocation. Returns the result -/// of expansion and the mark which must be applied to the result. -/// Our current interface doesn't allow us to apply the mark to the -/// result until after calling make_expr, make_items, etc. -fn expand_mac_invoc(mac: ast::Mac, - span: codemap::Span, - parse_thunk: F, - mark_thunk: G, - fld: &mut MacroExpander) - -> Option where - F: for<'a> FnOnce(Box) -> Option, - G: FnOnce(T, Mrk) -> T, -{ +/// Expand a (not-ident-style) macro invocation. Returns the result of expansion. +fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut MacroExpander) + -> Option { // it would almost certainly be cleaner to pass the whole // macro invocation in, rather than pulling it apart and // marking the tts and the ctxt separately. This also goes @@ -245,7 +267,7 @@ fn expand_mac_invoc(mac: ast::Mac, let expanded = expandfun.expand(fld.cx, mac_span, &marked_before[..]); - parse_thunk(expanded) + T::make_with(expanded) }; let parsed = match opt_parsed { Some(e) => e, @@ -258,7 +280,7 @@ fn expand_mac_invoc(mac: ast::Mac, return None; } }; - Some(mark_thunk(parsed,fm)) + Some(parsed.fold_with(&mut Marker { mark: fm })) } _ => { fld.cx.span_err( @@ -523,11 +545,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { // Assert that we drop any macro attributes on the floor here drop(attrs); - let maybe_new_items = - expand_mac_invoc(mac.unwrap(), stmt.span, - |r| r.make_stmts(), - |stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)), - fld); + let maybe_new_items: Option> = + expand_mac_invoc(mac.unwrap(), stmt.span, fld); let mut fully_expanded = match maybe_new_items { Some(stmts) => { @@ -759,6 +778,7 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P { PatKind::Mac(mac) => (mac.node.path, mac.node.tts), _ => unreachable!() }; + if pth.segments.len() > 1 { fld.cx.span_err(pth.span, "expected macro name without module separators"); return DummyResult::raw_pat(span); @@ -1079,11 +1099,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) ast::ImplItemKind::Macro(mac) => { check_attributes(&ii.attrs, fld); - let maybe_new_items = - expand_mac_invoc(mac, ii.span, - |r| r.make_impl_items(), - |meths, mark| meths.move_map(|m| mark_impl_item(m, mark)), - fld); + let maybe_new_items: Option> = + expand_mac_invoc(mac, ii.span, fld); match maybe_new_items { Some(impl_items) => { @@ -1139,10 +1156,7 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P { let t = match t.node.clone() { ast::TyKind::Mac(mac) => { if fld.cx.ecfg.features.unwrap().type_macros { - let expanded_ty = match expand_mac_invoc(mac, t.span, - |r| r.make_ty(), - mark_ty, - fld) { + let expanded_ty = match expand_mac_invoc(mac, t.span, fld) { Some(ty) => ty, None => { return DummyResult::raw_ty(t.span); @@ -1426,38 +1440,17 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec { noop_fold_tts(tts, &mut Marker{mark:m}) } -// apply a given mark to the given expr. Used following the expansion of a macro. -fn mark_expr(expr: P, m: Mrk) -> P { - Marker{mark:m}.fold_expr(expr) -} - // apply a given mark to the given pattern. Used following the expansion of a macro. fn mark_pat(pat: P, m: Mrk) -> P { Marker{mark:m}.fold_pat(pat) } -// apply a given mark to the given stmt. Used following the expansion of a macro. -fn mark_stmt(stmt: ast::Stmt, m: Mrk) -> ast::Stmt { - Marker{mark:m}.fold_stmt(stmt) - .expect_one("marking a stmt didn't return exactly one stmt") -} - // apply a given mark to the given item. Used following the expansion of a macro. fn mark_item(expr: P, m: Mrk) -> P { Marker{mark:m}.fold_item(expr) .expect_one("marking an item didn't return exactly one item") } -// apply a given mark to the given item. Used following the expansion of a macro. -fn mark_impl_item(ii: ast::ImplItem, m: Mrk) -> ast::ImplItem { - Marker{mark:m}.fold_impl_item(ii) - .expect_one("marking an impl item didn't return exactly one impl item") -} - -fn mark_ty(ty: P, m: Mrk) -> P { - Marker { mark: m }.fold_ty(ty) -} - /// Check that there are no macro invocations left in the AST: pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) { visit::walk_crate(&mut MacroExterminator{sess:sess}, krate); From bd0e1fec72be32347350f320dcded01a3fe94e88 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 19 May 2016 10:30:34 +0000 Subject: [PATCH 042/179] Improve diagnostics --- src/libsyntax/ext/expand.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b2ebe0e0145f..6c22fe4c8bcf 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -272,11 +272,9 @@ fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut Macr let parsed = match opt_parsed { Some(e) => e, None => { - fld.cx.span_err( - pth.span, - &format!("non-expression macro in expression position: {}", - extname - )); + let msg = format!("non-{kind} macro in {kind} position: {name}", + name = extname, kind = T::kind_name()); + fld.cx.span_err(pth.span, &msg); return None; } }; From 20a3ee72826b6c60326b96116a18177270ef675c Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 20 May 2016 23:35:56 +0000 Subject: [PATCH 043/179] Re-fold expanded items in `expand_mac_invoc` --- src/libsyntax/ext/expand.rs | 76 +++++++------------------------------ 1 file changed, 13 insertions(+), 63 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 6c22fe4c8bcf..8833b901ec73 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -93,18 +93,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // Assert that we drop any macro attributes on the floor here drop(attrs); - let expanded_expr = match expand_mac_invoc(mac, span, fld) { - Some(expr) => expr, - None => { - return DummyResult::raw_expr(span); - } - }; - - // Keep going, outside-in. - let fully_expanded = fld.fold_expr(expanded_expr); - fld.cx.bt_pop(); - - fully_expanded + expand_mac_invoc(mac, span, fld) } ast::ExprKind::InPlace(placer, value_expr) => { @@ -215,8 +204,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { } /// Expand a (not-ident-style) macro invocation. Returns the result of expansion. -fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut MacroExpander) - -> Option { +fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut MacroExpander) -> T { // it would almost certainly be cleaner to pass the whole // macro invocation in, rather than pulling it apart and // marking the tts and the ctxt separately. This also goes @@ -229,7 +217,7 @@ fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut Macr "expected macro name without module \ separators"); // let compilation continue - return None; + return T::dummy(span); } let extname = pth.segments[0].identifier.name; match fld.cx.syntax_env.find(extname) { @@ -242,7 +230,7 @@ fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut Macr err.emit(); // let compilation continue - None + T::dummy(span) } Some(rc) => match *rc { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { @@ -275,17 +263,20 @@ fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut Macr let msg = format!("non-{kind} macro in {kind} position: {name}", name = extname, kind = T::kind_name()); fld.cx.span_err(pth.span, &msg); - return None; + return T::dummy(span); } }; - Some(parsed.fold_with(&mut Marker { mark: fm })) + let marked = parsed.fold_with(&mut Marker { mark: fm }); + let fully_expanded = marked.fold_with(fld); + fld.cx.bt_pop(); + fully_expanded } _ => { fld.cx.span_err( pth.span, &format!("'{}' is not a tt-style macro", extname)); - None + T::dummy(span) } } } @@ -543,21 +534,9 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { // Assert that we drop any macro attributes on the floor here drop(attrs); - let maybe_new_items: Option> = + let mut fully_expanded: SmallVector = expand_mac_invoc(mac.unwrap(), stmt.span, fld); - let mut fully_expanded = match maybe_new_items { - Some(stmts) => { - // Keep going, outside-in. - let new_items = stmts.into_iter().flat_map(|s| { - fld.fold_stmt(s).into_iter() - }).collect(); - fld.cx.bt_pop(); - new_items - } - None => SmallVector::zero() - }; - // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. if style == MacStmtStyle::Semicolon { @@ -1096,21 +1075,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) }), ast::ImplItemKind::Macro(mac) => { check_attributes(&ii.attrs, fld); - - let maybe_new_items: Option> = - expand_mac_invoc(mac, ii.span, fld); - - match maybe_new_items { - Some(impl_items) => { - // expand again if necessary - let new_items = impl_items.into_iter().flat_map(|ii| { - expand_impl_item(ii, fld).into_iter() - }).collect(); - fld.cx.bt_pop(); - new_items - } - None => SmallVector::zero() - } + expand_mac_invoc(mac, ii.span, fld) } _ => fold::noop_fold_impl_item(ii, fld) } @@ -1154,22 +1119,7 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P { let t = match t.node.clone() { ast::TyKind::Mac(mac) => { if fld.cx.ecfg.features.unwrap().type_macros { - let expanded_ty = match expand_mac_invoc(mac, t.span, fld) { - Some(ty) => ty, - None => { - return DummyResult::raw_ty(t.span); - } - }; - - // Keep going, outside-in. - let fully_expanded = fld.fold_ty(expanded_ty); - fld.cx.bt_pop(); - - fully_expanded.map(|t| ast::Ty { - id: ast::DUMMY_NODE_ID, - node: t.node, - span: t.span, - }) + expand_mac_invoc(mac, t.span, fld) } else { feature_gate::emit_feature_err( &fld.cx.parse_sess.span_diagnostic, From a88b7f1d4daef01f21c21d85a9c095181a1c82d7 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 19 May 2016 10:18:54 +0000 Subject: [PATCH 044/179] Use `expand_mac_invoc` in `expand_pat` --- src/libsyntax/ext/expand.rs | 78 ++----------------------------------- 1 file changed, 3 insertions(+), 75 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8833b901ec73..8a5689daca51 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -750,77 +750,10 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P { PatKind::Mac(_) => {} _ => return noop_fold_pat(p, fld) } - p.map(|ast::Pat {node, span, ..}| { - let (pth, tts) = match node { - PatKind::Mac(mac) => (mac.node.path, mac.node.tts), + p.and_then(|ast::Pat {node, span, ..}| { + match node { + PatKind::Mac(mac) => expand_mac_invoc(mac, span, fld), _ => unreachable!() - }; - - if pth.segments.len() > 1 { - fld.cx.span_err(pth.span, "expected macro name without module separators"); - return DummyResult::raw_pat(span); - } - let extname = pth.segments[0].identifier.name; - let marked_after = match fld.cx.syntax_env.find(extname) { - None => { - fld.cx.span_err(pth.span, - &format!("macro undefined: '{}!'", - extname)); - // let compilation continue - return DummyResult::raw_pat(span); - } - - Some(rc) => match *rc { - NormalTT(ref expander, tt_span, allow_internal_unstable) => { - fld.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: tt_span, - allow_internal_unstable: allow_internal_unstable, - } - }); - - let fm = fresh_mark(); - let marked_before = mark_tts(&tts[..], fm); - let mac_span = fld.cx.original_span(); - let pat = expander.expand(fld.cx, - mac_span, - &marked_before[..]).make_pat(); - let expanded = match pat { - Some(e) => e, - None => { - fld.cx.span_err( - pth.span, - &format!( - "non-pattern macro in pattern position: {}", - extname - ) - ); - return DummyResult::raw_pat(span); - } - }; - - // mark after: - mark_pat(expanded,fm) - } - _ => { - fld.cx.span_err(span, - &format!("{}! is not legal in pattern position", - extname)); - return DummyResult::raw_pat(span); - } - } - }; - - let fully_expanded = - fld.fold_pat(marked_after).node.clone(); - fld.cx.bt_pop(); - - ast::Pat { - id: ast::DUMMY_NODE_ID, - node: fully_expanded, - span: span } }) } @@ -1388,11 +1321,6 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec { noop_fold_tts(tts, &mut Marker{mark:m}) } -// apply a given mark to the given pattern. Used following the expansion of a macro. -fn mark_pat(pat: P, m: Mrk) -> P { - Marker{mark:m}.fold_pat(pat) -} - // apply a given mark to the given item. Used following the expansion of a macro. fn mark_item(expr: P, m: Mrk) -> P { Marker{mark:m}.fold_item(expr) From 744877ba22982dfa02557f3c899f562c7a1fb9d8 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 20 May 2016 23:55:39 +0000 Subject: [PATCH 045/179] Check attributes in `expand_mac_invoc` --- src/libsyntax/ext/expand.rs | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8a5689daca51..aa5d93d82695 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -16,7 +16,7 @@ use ast; use ext::mtwt; use ext::build::AstBuilder; use attr; -use attr::{AttrMetaMethods, WithAttrs}; +use attr::{AttrMetaMethods, WithAttrs, ThinAttributesExt}; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; @@ -86,14 +86,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprKind::Mac(mac) => { - if let Some(ref attrs) = attrs { - check_attributes(attrs, fld); - } - - // Assert that we drop any macro attributes on the floor here - drop(attrs); - - expand_mac_invoc(mac, span, fld) + expand_mac_invoc(mac, attrs.into_attr_vec(), span, fld) } ast::ExprKind::InPlace(placer, value_expr) => { @@ -204,7 +197,12 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { } /// Expand a (not-ident-style) macro invocation. Returns the result of expansion. -fn expand_mac_invoc(mac: ast::Mac, span: Span, fld: &mut MacroExpander) -> T { +fn expand_mac_invoc(mac: ast::Mac, attrs: Vec, span: Span, + fld: &mut MacroExpander) -> T + where T: MacroGenerable, +{ + check_attributes(&attrs, fld); + // it would almost certainly be cleaner to pass the whole // macro invocation in, rather than pulling it apart and // marking the tts and the ctxt separately. This also goes @@ -527,15 +525,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { _ => return expand_non_macro_stmt(stmt, fld) }; - if let Some(ref attrs) = attrs { - check_attributes(attrs, fld); - } - - // Assert that we drop any macro attributes on the floor here - drop(attrs); - let mut fully_expanded: SmallVector = - expand_mac_invoc(mac.unwrap(), stmt.span, fld); + expand_mac_invoc(mac.unwrap(), attrs.into_attr_vec(), stmt.span, fld); // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. @@ -752,7 +743,7 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P { } p.and_then(|ast::Pat {node, span, ..}| { match node { - PatKind::Mac(mac) => expand_mac_invoc(mac, span, fld), + PatKind::Mac(mac) => expand_mac_invoc(mac, Vec::new(), span, fld), _ => unreachable!() } }) @@ -1007,8 +998,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) span: fld.new_span(ii.span) }), ast::ImplItemKind::Macro(mac) => { - check_attributes(&ii.attrs, fld); - expand_mac_invoc(mac, ii.span, fld) + expand_mac_invoc(mac, ii.attrs, ii.span, fld) } _ => fold::noop_fold_impl_item(ii, fld) } @@ -1052,7 +1042,7 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P { let t = match t.node.clone() { ast::TyKind::Mac(mac) => { if fld.cx.ecfg.features.unwrap().type_macros { - expand_mac_invoc(mac, t.span, fld) + expand_mac_invoc(mac, Vec::new(), t.span, fld) } else { feature_gate::emit_feature_err( &fld.cx.parse_sess.span_diagnostic, From 7ac2ae60b3015f21672695be87721e80d569cbfb Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 21 May 2016 00:15:00 +0000 Subject: [PATCH 046/179] Refactor out `mac_result` in `expand_mac_invoc` --- src/libsyntax/ext/expand.rs | 107 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index aa5d93d82695..952d398e5bdd 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -201,47 +201,46 @@ fn expand_mac_invoc(mac: ast::Mac, attrs: Vec, span: Span, fld: &mut MacroExpander) -> T where T: MacroGenerable, { - check_attributes(&attrs, fld); - // it would almost certainly be cleaner to pass the whole // macro invocation in, rather than pulling it apart and // marking the tts and the ctxt separately. This also goes // for the other three macro invocation chunks of code // in this file. - let Mac_ { path: pth, tts, .. } = mac.node; - if pth.segments.len() > 1 { - fld.cx.span_err(pth.span, - "expected macro name without module \ - separators"); - // let compilation continue - return T::dummy(span); - } - let extname = pth.segments[0].identifier.name; - match fld.cx.syntax_env.find(extname) { - None => { - let mut err = fld.cx.struct_span_err( - pth.span, - &format!("macro undefined: '{}!'", - &extname)); + let Mac_ { path, tts, .. } = mac.node; + let mark = fresh_mark(); + + fn mac_result<'a>(path: &ast::Path, tts: Vec, mark: Mrk, + attrs: Vec, call_site: Span, fld: &'a mut MacroExpander) + -> Option> { + check_attributes(&attrs, fld); + + if path.segments.len() > 1 { + fld.cx.span_err(path.span, "expected macro name without module separators"); + return None; + } + + let extname = path.segments[0].identifier.name; + let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) { + extension + } else { + let mut err = fld.cx.struct_span_err(path.span, + &format!("macro undefined: '{}!'", &extname)); fld.cx.suggest_macro_name(&extname.as_str(), &mut err); err.emit(); + return None; + }; - // let compilation continue - T::dummy(span) - } - Some(rc) => match *rc { + match *extension { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { fld.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: exp_span, - allow_internal_unstable: allow_internal_unstable, - }, - }); - let fm = fresh_mark(); - let marked_before = mark_tts(&tts[..], fm); + call_site: call_site, + callee: NameAndSpan { + format: MacroBang(extname), + span: exp_span, + allow_internal_unstable: allow_internal_unstable, + }, + }); // The span that we pass to the expanders we want to // be the root of the call stack. That's the most @@ -249,35 +248,35 @@ fn expand_mac_invoc(mac: ast::Mac, attrs: Vec, span: Span, // the macro. let mac_span = fld.cx.original_span(); - let opt_parsed = { - let expanded = expandfun.expand(fld.cx, - mac_span, - &marked_before[..]); - T::make_with(expanded) - }; - let parsed = match opt_parsed { - Some(e) => e, - None => { - let msg = format!("non-{kind} macro in {kind} position: {name}", - name = extname, kind = T::kind_name()); - fld.cx.span_err(pth.span, &msg); - return T::dummy(span); - } - }; - let marked = parsed.fold_with(&mut Marker { mark: fm }); - let fully_expanded = marked.fold_with(fld); - fld.cx.bt_pop(); - fully_expanded + let marked_tts = mark_tts(&tts[..], mark); + Some(expandfun.expand(fld.cx, mac_span, &marked_tts)) } _ => { - fld.cx.span_err( - pth.span, - &format!("'{}' is not a tt-style macro", - extname)); - T::dummy(span) + fld.cx.span_err(path.span, + &format!("'{}' is not a tt-style macro", extname)); + None } } } + + let opt_expanded = T::make_with(match mac_result(&path, tts, mark, attrs, span, fld) { + Some(result) => result, + None => return T::dummy(span), + }); + + let expanded = if let Some(expanded) = opt_expanded { + expanded + } else { + let msg = format!("non-{kind} macro in {kind} position: {name}", + name = path.segments[0].identifier.name, kind = T::kind_name()); + fld.cx.span_err(path.span, &msg); + return T::dummy(span); + }; + + let marked = expanded.fold_with(&mut Marker { mark: mark }); + let fully_expanded = marked.fold_with(fld); + fld.cx.bt_pop(); + fully_expanded } /// Rename loop label and expand its loop body From d32b9858b9acc6e8dcd73357592e328507f97249 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 21 May 2016 00:19:00 +0000 Subject: [PATCH 047/179] Refactor away `expand_item_mac` --- src/libsyntax/ext/expand.rs | 244 +++++++++++++----------------------- 1 file changed, 85 insertions(+), 159 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 952d398e5bdd..c8272316c3c7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -86,7 +86,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprKind::Mac(mac) => { - expand_mac_invoc(mac, attrs.into_attr_vec(), span, fld) + expand_mac_invoc(mac, None, attrs.into_attr_vec(), span, fld) } ast::ExprKind::InPlace(placer, value_expr) => { @@ -196,21 +196,17 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }); } -/// Expand a (not-ident-style) macro invocation. Returns the result of expansion. -fn expand_mac_invoc(mac: ast::Mac, attrs: Vec, span: Span, +/// Expand a macro invocation. Returns the result of expansion. +fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec, span: Span, fld: &mut MacroExpander) -> T where T: MacroGenerable, { - // it would almost certainly be cleaner to pass the whole - // macro invocation in, rather than pulling it apart and - // marking the tts and the ctxt separately. This also goes - // for the other three macro invocation chunks of code - // in this file. - + // It would almost certainly be cleaner to pass the whole macro invocation in, + // rather than pulling it apart and marking the tts and the ctxt separately. let Mac_ { path, tts, .. } = mac.node; let mark = fresh_mark(); - fn mac_result<'a>(path: &ast::Path, tts: Vec, mark: Mrk, + fn mac_result<'a>(path: &ast::Path, ident: Option, tts: Vec, mark: Mrk, attrs: Vec, call_site: Span, fld: &'a mut MacroExpander) -> Option> { check_attributes(&attrs, fld); @@ -231,8 +227,16 @@ fn expand_mac_invoc(mac: ast::Mac, attrs: Vec, span: Span, return None; }; + let ident = ident.unwrap_or(Ident::with_empty_ctxt(keywords::Invalid.name())); match *extension { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { + if ident.name != keywords::Invalid.name() { + let msg = + format!("macro {}! expects no ident argument, given '{}'", extname, ident); + fld.cx.span_err(path.span, &msg); + return None; + } + fld.cx.bt_push(ExpnInfo { call_site: call_site, callee: NameAndSpan { @@ -251,15 +255,72 @@ fn expand_mac_invoc(mac: ast::Mac, attrs: Vec, span: Span, let marked_tts = mark_tts(&tts[..], mark); Some(expandfun.expand(fld.cx, mac_span, &marked_tts)) } - _ => { + + IdentTT(ref expander, tt_span, allow_internal_unstable) => { + if ident.name == keywords::Invalid.name() { + fld.cx.span_err(path.span, + &format!("macro {}! expects an ident argument", extname)); + return None; + }; + + fld.cx.bt_push(ExpnInfo { + call_site: call_site, + callee: NameAndSpan { + format: MacroBang(extname), + span: tt_span, + allow_internal_unstable: allow_internal_unstable, + } + }); + + let marked_tts = mark_tts(&tts, mark); + Some(expander.expand(fld.cx, call_site, ident, marked_tts)) + } + + MacroRulesTT => { + if ident.name == keywords::Invalid.name() { + fld.cx.span_err(path.span, + &format!("macro {}! expects an ident argument", extname)); + return None; + }; + + fld.cx.bt_push(ExpnInfo { + call_site: call_site, + callee: NameAndSpan { + format: MacroBang(extname), + span: None, + // `macro_rules!` doesn't directly allow unstable + // (this is orthogonal to whether the macro it creates allows it) + allow_internal_unstable: false, + } + }); + + // DON'T mark before expansion. + fld.cx.insert_macro(ast::MacroDef { + ident: ident, + id: ast::DUMMY_NODE_ID, + span: call_site, + imported_from: None, + use_locally: true, + body: tts, + export: attr::contains_name(&attrs, "macro_export"), + allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), + attrs: attrs, + }); + + // macro_rules! has a side effect but expands to nothing. + fld.cx.bt_pop(); + None + } + + MultiDecorator(..) | MultiModifier(..) => { fld.cx.span_err(path.span, - &format!("'{}' is not a tt-style macro", extname)); + &format!("`{}` can only be used in attributes", extname)); None } } } - let opt_expanded = T::make_with(match mac_result(&path, tts, mark, attrs, span, fld) { + let opt_expanded = T::make_with(match mac_result(&path, ident, tts, mark, attrs, span, fld) { Some(result) => result, None => return T::dummy(span), }); @@ -375,141 +436,6 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool false } -// Support for item-position macro invocations, exactly the same -// logic as for expression-position macro invocations. -pub fn expand_item_mac(it: P, - fld: &mut MacroExpander) -> SmallVector> { - let (extname, path_span, tts, span, attrs, ident) = it.and_then(|it| match it.node { - ItemKind::Mac(codemap::Spanned { node: Mac_ { path, tts, .. }, .. }) => - (path.segments[0].identifier.name, path.span, tts, it.span, it.attrs, it.ident), - _ => fld.cx.span_bug(it.span, "invalid item macro invocation") - }); - - check_attributes(&attrs, fld); - - let fm = fresh_mark(); - let items = { - let expanded = match fld.cx.syntax_env.find(extname) { - None => { - fld.cx.span_err(path_span, - &format!("macro undefined: '{}!'", - extname)); - // let compilation continue - return SmallVector::zero(); - } - - Some(rc) => match *rc { - NormalTT(ref expander, tt_span, allow_internal_unstable) => { - if ident.name != keywords::Invalid.name() { - fld.cx - .span_err(path_span, - &format!("macro {}! expects no ident argument, given '{}'", - extname, - ident)); - return SmallVector::zero(); - } - fld.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: tt_span, - allow_internal_unstable: allow_internal_unstable, - } - }); - // mark before expansion: - let marked_before = mark_tts(&tts[..], fm); - expander.expand(fld.cx, span, &marked_before[..]) - } - IdentTT(ref expander, tt_span, allow_internal_unstable) => { - if ident.name == keywords::Invalid.name() { - fld.cx.span_err(path_span, - &format!("macro {}! expects an ident argument", - extname)); - return SmallVector::zero(); - } - fld.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: tt_span, - allow_internal_unstable: allow_internal_unstable, - } - }); - // mark before expansion: - let marked_tts = mark_tts(&tts[..], fm); - expander.expand(fld.cx, span, ident, marked_tts) - } - MacroRulesTT => { - if ident.name == keywords::Invalid.name() { - fld.cx.span_err(path_span, "macro_rules! expects an ident argument"); - return SmallVector::zero(); - } - - fld.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: None, - // `macro_rules!` doesn't directly allow - // unstable (this is orthogonal to whether - // the macro it creates allows it) - allow_internal_unstable: false, - } - }); - // DON'T mark before expansion. - - let allow_internal_unstable = attr::contains_name(&attrs, - "allow_internal_unstable"); - - let export = attr::contains_name(&attrs, "macro_export"); - let def = ast::MacroDef { - ident: ident, - attrs: attrs, - id: ast::DUMMY_NODE_ID, - span: span, - imported_from: None, - export: export, - use_locally: true, - allow_internal_unstable: allow_internal_unstable, - body: tts, - }; - fld.cx.insert_macro(def); - - // macro_rules! has a side effect but expands to nothing. - fld.cx.bt_pop(); - return SmallVector::zero(); - } - _ => { - fld.cx.span_err(span, - &format!("{}! is not legal in item position", - extname)); - return SmallVector::zero(); - } - } - }; - - expanded.make_items() - }; - - let items = match items { - Some(items) => { - items.into_iter() - .map(|i| mark_item(i, fm)) - .flat_map(|i| fld.fold_item(i).into_iter()) - .collect() - } - None => { - fld.cx.span_err(path_span, - &format!("non-item macro in item position: {}", - extname)); - return SmallVector::zero(); - } - }; - - fld.cx.bt_pop(); - items -} - /// Expand a stmt fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { // perform all pending renames @@ -525,7 +451,7 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { }; let mut fully_expanded: SmallVector = - expand_mac_invoc(mac.unwrap(), attrs.into_attr_vec(), stmt.span, fld); + expand_mac_invoc(mac.unwrap(), None, attrs.into_attr_vec(), stmt.span, fld); // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. @@ -742,7 +668,7 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P { } p.and_then(|ast::Pat {node, span, ..}| { match node { - PatKind::Mac(mac) => expand_mac_invoc(mac, Vec::new(), span, fld), + PatKind::Mac(mac) => expand_mac_invoc(mac, None, Vec::new(), span, fld), _ => unreachable!() } }) @@ -813,7 +739,13 @@ fn expand_annotatable(a: Annotatable, let mut new_items: SmallVector = match a { Annotatable::Item(it) => match it.node { ast::ItemKind::Mac(..) => { - expand_item_mac(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect() + let new_items: SmallVector> = it.and_then(|it| match it.node { + ItemKind::Mac(mac) => + expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld), + _ => unreachable!(), + }); + + new_items.into_iter().map(|i| Annotatable::Item(i)).collect() } ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => { let valid_ident = @@ -997,7 +929,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) span: fld.new_span(ii.span) }), ast::ImplItemKind::Macro(mac) => { - expand_mac_invoc(mac, ii.attrs, ii.span, fld) + expand_mac_invoc(mac, None, ii.attrs, ii.span, fld) } _ => fold::noop_fold_impl_item(ii, fld) } @@ -1041,7 +973,7 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P { let t = match t.node.clone() { ast::TyKind::Mac(mac) => { if fld.cx.ecfg.features.unwrap().type_macros { - expand_mac_invoc(mac, Vec::new(), t.span, fld) + expand_mac_invoc(mac, None, Vec::new(), t.span, fld) } else { feature_gate::emit_feature_err( &fld.cx.parse_sess.span_diagnostic, @@ -1310,12 +1242,6 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec { noop_fold_tts(tts, &mut Marker{mark:m}) } -// apply a given mark to the given item. Used following the expansion of a macro. -fn mark_item(expr: P, m: Mrk) -> P { - Marker{mark:m}.fold_item(expr) - .expect_one("marking an item didn't return exactly one item") -} - /// Check that there are no macro invocations left in the AST: pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) { visit::walk_crate(&mut MacroExterminator{sess:sess}, krate); From 4afdae86600f6fdb1a67ebaf0c8be218951ecd95 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 21 May 2016 01:26:30 +0000 Subject: [PATCH 048/179] Refactor away `check_attributes` --- src/libsyntax/ext/expand.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c8272316c3c7..9bfeb81b74a9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -69,16 +69,6 @@ impl_macro_generable! { "statement", .make_stmts, lift .fold_stmt, |_span| SmallVector::zero(); } -// this function is called to detect use of feature-gated or invalid attributes -// on macro invoations since they will not be detected after macro expansion -fn check_attributes(attrs: &[ast::Attribute], fld: &MacroExpander) { - for attr in attrs.iter() { - feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic, - &fld.cx.parse_sess.codemap(), - &fld.cx.ecfg.features.unwrap()); - } -} - pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let expr_span = e.span; return e.and_then(|ast::Expr {id, node, span, attrs}| match node { @@ -209,7 +199,13 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec(path: &ast::Path, ident: Option, tts: Vec, mark: Mrk, attrs: Vec, call_site: Span, fld: &'a mut MacroExpander) -> Option> { - check_attributes(&attrs, fld); + // Detect use of feature-gated or invalid attributes on macro invoations + // since they will not be detected after macro expansion. + for attr in attrs.iter() { + feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic, + &fld.cx.parse_sess.codemap(), + &fld.cx.ecfg.features.unwrap()); + } if path.segments.len() > 1 { fld.cx.span_err(path.span, "expected macro name without module separators"); From 67f4fd053100fdbb39de77bebfdc5f52b515bfda Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 21 May 2016 08:39:33 +0000 Subject: [PATCH 049/179] Move `placement_in_syntax` gated feature checking from expansion to the post-expansion visitor --- src/libsyntax/ext/expand.rs | 16 ---------------- src/libsyntax/feature_gate.rs | 3 +++ 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9bfeb81b74a9..df1bbf5f26ec 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -70,7 +70,6 @@ impl_macro_generable! { } pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { - let expr_span = e.span; return e.and_then(|ast::Expr {id, node, span, attrs}| match node { // expr_mac should really be expr_ext or something; it's the @@ -79,21 +78,6 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { expand_mac_invoc(mac, None, attrs.into_attr_vec(), span, fld) } - ast::ExprKind::InPlace(placer, value_expr) => { - // Ensure feature-gate is enabled - if !fld.cx.ecfg.features.unwrap().placement_in_syntax { - feature_gate::emit_feature_err( - &fld.cx.parse_sess.span_diagnostic, "placement_in_syntax", expr_span, - feature_gate::GateIssue::Language, feature_gate::EXPLAIN_PLACEMENT_IN - ); - } - - let placer = fld.fold_expr(placer); - let value_expr = fld.fold_expr(value_expr); - fld.cx.expr(span, ast::ExprKind::InPlace(placer, value_expr)) - .with_attrs(fold_thin_attrs(attrs, fld)) - } - ast::ExprKind::While(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index acef98f2afc1..dbef06f7aa49 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -997,6 +997,9 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { ast::ExprKind::Try(..) => { gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable"); } + ast::ExprKind::InPlace(..) => { + gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); + } _ => {} } visit::walk_expr(self, e); From 4ed4abc0ea871be7300f24ea0fd85f48e957fa1d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 21 May 2016 01:58:42 +0000 Subject: [PATCH 050/179] Test diagnostics --- src/test/compile-fail/macro-error.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/macro-error.rs b/src/test/compile-fail/macro-error.rs index 817b675aedfe..a69188da58d1 100644 --- a/src/test/compile-fail/macro-error.rs +++ b/src/test/compile-fail/macro-error.rs @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that we report errors at macro definition, not expansion. +#![feature(type_macros)] macro_rules! foo { ($a:expr) => $a; //~ ERROR macro rhs must be delimited } fn main() { - foo!(0); + foo!(0); // Check that we report errors at macro definition, not expansion. + + let _: cfg!(foo) = (); //~ ERROR non-type macro in type position + derive!(); //~ ERROR `derive` can only be used in attributes } From 2314f5432b943da24ed4f2eb41772047b0dd0b8f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 May 2016 01:13:26 +0200 Subject: [PATCH 051/179] Update repr_simd --- src/librustc_typeck/diagnostics.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 45aec9558fea..dbdbd32372a4 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -978,18 +978,18 @@ are generic. This will cause an error: ```compile_fail -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct Bad(T, T, T); ``` This will not: ``` -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct Good(u32, u32, u32); ``` "##, @@ -1026,18 +1026,18 @@ will trigger this error. This will cause an error: ```compile_fail -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct Bad(u16, u32, u32); ``` This will not: ``` -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct Good(u32, u32, u32); ``` "##, @@ -1049,18 +1049,18 @@ must be machine types so SIMD operations can be applied to them. This will cause an error: ```compile_fail -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct Bad(String); ``` This will not: ``` -#![feature(simd)] +#![feature(repr_simd)] -#[simd] +#[repr(simd)] struct Good(u32, u32, u32); ``` "##, From a235ed3392de9f677440fd9b6f54a7e81b1c00a0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 21 May 2016 16:36:25 -0700 Subject: [PATCH 052/179] mk: Add --enable-local-rebuild to bootstrap from the current release In Linux distributions, it is often necessary to rebuild packages for cases like applying new patches or linking against new system libraries. In this scenario, the rustc in the distro build environment may already match the current release that we're trying to rebuild. Thus we don't want to use the prior release's bootstrap key, nor `--cfg stage0` for the prior unstable features. The new `configure --enable-local-rebuild` option specifies that we are rebuilding from the current release. The current bootstrap key is used for the local rustc, and current stage1 features are also assumed. --- configure | 11 +++++++++++ mk/main.mk | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/configure b/configure index 38f3e3b00c6d..b7053c5c54f5 100755 --- a/configure +++ b/configure @@ -599,6 +599,7 @@ opt debug-assertions 0 "build with debugging assertions" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" +opt local-rebuild 0 "use an installed rustc matching the current version, for rebuilds" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt rpath 1 "build rpaths into rustc itself" opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" @@ -847,6 +848,16 @@ then BIN_SUF=.exe fi +# --enable-local-rebuild implies --enable-local-rust too +if [ -n "$CFG_ENABLE_LOCAL_REBUILD" ] +then + if [ -z "$CFG_ENABLE_LOCAL_RUST" ] + then + CFG_ENABLE_LOCAL_RUST=1 + putvar CFG_ENABLE_LOCAL_RUST + fi +fi + if [ -n "$CFG_ENABLE_LOCAL_RUST" ] then system_rustc=$(which rustc) diff --git a/mk/main.mk b/mk/main.mk index 493b61051331..6feb53ec7b17 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -34,7 +34,14 @@ CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(C # intentionally not "secure" by any definition, this is largely just a deterrent # from users enabling unstable features on the stable compiler. CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA) + +# The stage0 compiler needs to use the previous key recorded in src/stage0.txt, +# except for local-rebuild when it just uses the same current key. +ifdef CFG_ENABLE_LOCAL_REBUILD +CFG_BOOTSTRAP_KEY_STAGE0=$(CFG_BOOTSTRAP_KEY) +else CFG_BOOTSTRAP_KEY_STAGE0=$(shell grep 'rustc_key' $(S)src/stage0.txt | sed 's/rustc_key: '//) +endif ifeq ($(CFG_RELEASE_CHANNEL),stable) # This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly" @@ -526,6 +533,11 @@ ifneq ($(strip $(CFG_BUILD)),$(strip $(3))) CFGFLAG$(1)_T_$(2)_H_$(3) = stage1 RPATH_VAR$(1)_T_$(2)_H_$(3) := $$(TARGET_RPATH_VAR1_T_$(2)_H_$$(CFG_BUILD)) +else +ifdef CFG_ENABLE_LOCAL_REBUILD +# Assume the local-rebuild rustc already has stage1 features too. +CFGFLAG$(1)_T_$(2)_H_$(3) = stage1 +endif endif endif From 8a299e8d5aa1d2cdc19a3044b10d3b8bf3f5a914 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 21 May 2016 16:46:04 -0700 Subject: [PATCH 053/179] bootstrap: mirror mk's local-rebuild changes The rustc for a local-rebuild is assumed to use the current bootstrap key and already match the current stage1 features. --- src/bootstrap/build/config.rs | 2 ++ src/bootstrap/build/mod.rs | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/build/config.rs b/src/bootstrap/build/config.rs index 3c35b9a95169..060fb5b8ef3d 100644 --- a/src/bootstrap/build/config.rs +++ b/src/bootstrap/build/config.rs @@ -67,6 +67,7 @@ pub struct Config { pub target: Vec, pub rustc: Option, pub cargo: Option, + pub rebuild: bool, // libstd features pub debug_jemalloc: bool, @@ -315,6 +316,7 @@ impl Config { ("RPATH", self.rust_rpath), ("OPTIMIZE_TESTS", self.rust_optimize_tests), ("DEBUGINFO_TESTS", self.rust_debuginfo_tests), + ("LOCAL_REBUILD", self.rebuild), } match key { diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index ebc05c5f61c5..9d5a093ab9e0 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -510,6 +510,14 @@ impl Build { .arg("-j").arg(self.jobs().to_string()) .arg("--target").arg(target); + let stage; + if compiler.stage == 0 && self.config.rebuild { + // Assume the local-rebuild rustc already has stage1 features. + stage = 1; + } else { + stage = compiler.stage; + } + // Customize the compiler we're running. Specify the compiler to cargo // as our shim and then pass it some various options used to configure // how the actual compiler itself is called. @@ -518,7 +526,7 @@ impl Build { // src/bootstrap/{rustc,rustdoc.rs} cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc")) .env("RUSTC_REAL", self.compiler_path(compiler)) - .env("RUSTC_STAGE", compiler.stage.to_string()) + .env("RUSTC_STAGE", stage.to_string()) .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) .env("RUSTC_CODEGEN_UNITS", self.config.rust_codegen_units.to_string()) @@ -744,7 +752,7 @@ impl Build { // In stage0 we're using a previously released stable compiler, so we // use the stage0 bootstrap key. Otherwise we use our own build's // bootstrap key. - let bootstrap_key = if compiler.is_snapshot(self) { + let bootstrap_key = if compiler.is_snapshot(self) && !self.config.rebuild { &self.bootstrap_key_stage0 } else { &self.bootstrap_key From cbd5db3bbcd27dd2bb18c348eabeb0be5aa066fd Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 20 May 2016 15:18:30 +0200 Subject: [PATCH 054/179] Add new error code tests --- src/test/compile-fail/E0062.rs | 20 ++++++++++++++++++++ src/test/compile-fail/E0063.rs | 18 ++++++++++++++++++ src/test/compile-fail/E0067.rs | 16 ++++++++++++++++ src/test/compile-fail/E0069.rs | 16 ++++++++++++++++ src/test/compile-fail/E0070.rs | 23 +++++++++++++++++++++++ src/test/compile-fail/E0071.rs | 16 ++++++++++++++++ src/test/compile-fail/E0072.rs | 17 +++++++++++++++++ src/test/compile-fail/E0075.rs | 17 +++++++++++++++++ src/test/compile-fail/E0076.rs | 17 +++++++++++++++++ src/test/compile-fail/E0077.rs | 17 +++++++++++++++++ src/test/compile-fail/E0079.rs | 16 ++++++++++++++++ src/test/compile-fail/E0080.rs | 17 +++++++++++++++++ src/test/compile-fail/E0081.rs | 18 ++++++++++++++++++ 13 files changed, 228 insertions(+) create mode 100644 src/test/compile-fail/E0062.rs create mode 100644 src/test/compile-fail/E0063.rs create mode 100644 src/test/compile-fail/E0067.rs create mode 100644 src/test/compile-fail/E0069.rs create mode 100644 src/test/compile-fail/E0070.rs create mode 100644 src/test/compile-fail/E0071.rs create mode 100644 src/test/compile-fail/E0072.rs create mode 100644 src/test/compile-fail/E0075.rs create mode 100644 src/test/compile-fail/E0076.rs create mode 100644 src/test/compile-fail/E0077.rs create mode 100644 src/test/compile-fail/E0079.rs create mode 100644 src/test/compile-fail/E0080.rs create mode 100644 src/test/compile-fail/E0081.rs diff --git a/src/test/compile-fail/E0062.rs b/src/test/compile-fail/E0062.rs new file mode 100644 index 000000000000..86ec7db14b5c --- /dev/null +++ b/src/test/compile-fail/E0062.rs @@ -0,0 +1,20 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + x: i32 +} + +fn main() { + let x = Foo { + x: 0, + x: 0, //~ ERROR E0062 + }; +} diff --git a/src/test/compile-fail/E0063.rs b/src/test/compile-fail/E0063.rs new file mode 100644 index 000000000000..c94f807d807c --- /dev/null +++ b/src/test/compile-fail/E0063.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + x: i32, + y: i32 +} + +fn main() { + let x = Foo { x: 0 }; //~ ERROR E0063 +} diff --git a/src/test/compile-fail/E0067.rs b/src/test/compile-fail/E0067.rs new file mode 100644 index 000000000000..a3fc30ee1c71 --- /dev/null +++ b/src/test/compile-fail/E0067.rs @@ -0,0 +1,16 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::LinkedList; + +fn main() { + LinkedList::new() += 1; //~ ERROR E0368 + //~^ ERROR E0067 +} diff --git a/src/test/compile-fail/E0069.rs b/src/test/compile-fail/E0069.rs new file mode 100644 index 000000000000..d164d8634878 --- /dev/null +++ b/src/test/compile-fail/E0069.rs @@ -0,0 +1,16 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> u8 { + return; //~ ERROR E0069 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0070.rs b/src/test/compile-fail/E0070.rs new file mode 100644 index 000000000000..ba66bd03aef9 --- /dev/null +++ b/src/test/compile-fail/E0070.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const SOME_CONST : i32 = 12; + +fn some_other_func() {} + +fn some_function() { + SOME_CONST = 14; //~ ERROR E0070 + 1 = 3; //~ ERROR E0070 + some_other_func() = 4; //~ ERROR E0070 + //~^ ERROR E0308 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0071.rs b/src/test/compile-fail/E0071.rs new file mode 100644 index 000000000000..658c8fb15511 --- /dev/null +++ b/src/test/compile-fail/E0071.rs @@ -0,0 +1,16 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { FirstValue(i32) } + +fn main() { + let u = Foo::FirstValue { value: 0 }; //~ ERROR E0071 + let t = u32 { value: 4 }; //~ ERROR E0071 +} diff --git a/src/test/compile-fail/E0072.rs b/src/test/compile-fail/E0072.rs new file mode 100644 index 000000000000..2f96ba1046d7 --- /dev/null +++ b/src/test/compile-fail/E0072.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct ListNode { //~ ERROR E0072 + head: u8, + tail: Option, +} + +fn main() { +} diff --git a/src/test/compile-fail/E0075.rs b/src/test/compile-fail/E0075.rs new file mode 100644 index 000000000000..d7783904e2e9 --- /dev/null +++ b/src/test/compile-fail/E0075.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad; //~ ERROR E0075 + +fn main() { +} diff --git a/src/test/compile-fail/E0076.rs b/src/test/compile-fail/E0076.rs new file mode 100644 index 000000000000..b0f02a03e005 --- /dev/null +++ b/src/test/compile-fail/E0076.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad(u16, u32, u32); //~ ERROR E0076 + +fn main() { +} diff --git a/src/test/compile-fail/E0077.rs b/src/test/compile-fail/E0077.rs new file mode 100644 index 000000000000..b074e90b2c01 --- /dev/null +++ b/src/test/compile-fail/E0077.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd)] + +#[repr(simd)] +struct Bad(String); //~ ERROR E0077 + +fn main() { +} diff --git a/src/test/compile-fail/E0079.rs b/src/test/compile-fail/E0079.rs new file mode 100644 index 000000000000..23957c72ff00 --- /dev/null +++ b/src/test/compile-fail/E0079.rs @@ -0,0 +1,16 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + Q = "32" //~ ERROR E0079 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0080.rs b/src/test/compile-fail/E0080.rs new file mode 100644 index 000000000000..0329209d44bc --- /dev/null +++ b/src/test/compile-fail/E0080.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Enum { + X = (1 << 500), //~ ERROR E0080 + Y = (1 / 0) //~ ERROR E0080 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0081.rs b/src/test/compile-fail/E0081.rs new file mode 100644 index 000000000000..b63265564b33 --- /dev/null +++ b/src/test/compile-fail/E0081.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Enum { + P = 3, + X = 3, //~ ERROR E0081 + Y = 5 +} + +fn main() { +} From 61acf1e496d82df4b05301960777ed901552f3c6 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Sun, 22 May 2016 23:57:13 +0530 Subject: [PATCH 055/179] run rustfmt on libcollections test module --- src/libcollectionstest/btree/map.rs | 118 +++++---- src/libcollectionstest/enum_set.rs | 115 ++++++-- src/libcollectionstest/linked_list.rs | 45 ++-- src/libcollectionstest/slice.rs | 366 ++++++++++++-------------- src/libcollectionstest/string.rs | 117 ++++---- src/libcollectionstest/vec.rs | 56 ++-- src/libcollectionstest/vec_deque.rs | 129 +++++---- 7 files changed, 522 insertions(+), 424 deletions(-) diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index 1858791776f0..e19090c7599e 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::collections::BTreeMap; -use std::collections::Bound::{Excluded, Included, Unbounded, self}; +use std::collections::Bound::{self, Excluded, Included, Unbounded}; use std::collections::btree_map::Entry::{Occupied, Vacant}; use std::rc::Rc; @@ -20,41 +20,41 @@ fn test_basic_large() { assert_eq!(map.len(), 0); for i in 0..size { - assert_eq!(map.insert(i, 10*i), None); + assert_eq!(map.insert(i, 10 * i), None); assert_eq!(map.len(), i + 1); } for i in 0..size { - assert_eq!(map.get(&i).unwrap(), &(i*10)); + assert_eq!(map.get(&i).unwrap(), &(i * 10)); } - for i in size..size*2 { + for i in size..size * 2 { assert_eq!(map.get(&i), None); } for i in 0..size { - assert_eq!(map.insert(i, 100*i), Some(10*i)); + assert_eq!(map.insert(i, 100 * i), Some(10 * i)); assert_eq!(map.len(), size); } for i in 0..size { - assert_eq!(map.get(&i).unwrap(), &(i*100)); + assert_eq!(map.get(&i).unwrap(), &(i * 100)); } - for i in 0..size/2 { - assert_eq!(map.remove(&(i*2)), Some(i*200)); + for i in 0..size / 2 { + assert_eq!(map.remove(&(i * 2)), Some(i * 200)); assert_eq!(map.len(), size - i - 1); } - for i in 0..size/2 { - assert_eq!(map.get(&(2*i)), None); - assert_eq!(map.get(&(2*i+1)).unwrap(), &(i*200 + 100)); + for i in 0..size / 2 { + assert_eq!(map.get(&(2 * i)), None); + assert_eq!(map.get(&(2 * i + 1)).unwrap(), &(i * 200 + 100)); } - for i in 0..size/2 { - assert_eq!(map.remove(&(2*i)), None); - assert_eq!(map.remove(&(2*i+1)), Some(i*200 + 100)); - assert_eq!(map.len(), size/2 - i - 1); + for i in 0..size / 2 { + assert_eq!(map.remove(&(2 * i)), None); + assert_eq!(map.remove(&(2 * i + 1)), Some(i * 200 + 100)); + assert_eq!(map.len(), size / 2 - i - 1); } } @@ -81,7 +81,9 @@ fn test_iter() { // Forwards let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - fn test(size: usize, mut iter: T) where T: Iterator { + fn test(size: usize, mut iter: T) + where T: Iterator + { for i in 0..size { assert_eq!(iter.size_hint(), (size - i, Some(size - i))); assert_eq!(iter.next().unwrap(), (i, i)); @@ -101,7 +103,9 @@ fn test_iter_rev() { // Forwards let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - fn test(size: usize, mut iter: T) where T: Iterator { + fn test(size: usize, mut iter: T) + where T: Iterator + { for i in 0..size { assert_eq!(iter.size_hint(), (size - i, Some(size - i))); assert_eq!(iter.next().unwrap(), (size - i - 1, size - i - 1)); @@ -125,8 +129,7 @@ fn test_values_mut() { } let values: Vec = a.values().cloned().collect(); - assert_eq!(values, [String::from("hello!"), - String::from("goodbye!")]); + assert_eq!(values, [String::from("hello!"), String::from("goodbye!")]); } #[test] @@ -137,7 +140,8 @@ fn test_iter_mixed() { let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); fn test(size: usize, mut iter: T) - where T: Iterator + DoubleEndedIterator { + where T: Iterator + DoubleEndedIterator + { for i in 0..size / 4 { assert_eq!(iter.size_hint(), (size - i * 2, Some(size - i * 2))); assert_eq!(iter.next().unwrap(), (i, i)); @@ -202,7 +206,7 @@ fn test_range() { for i in 0..size { for j in i..size { let mut kvs = map.range(Included(&i), Included(&j)).map(|(&k, &v)| (k, v)); - let mut pairs = (i..j+1).map(|i| (i, i)); + let mut pairs = (i..j + 1).map(|i| (i, i)); for (kv, pair) in kvs.by_ref().zip(pairs.by_ref()) { assert_eq!(kv, pair); @@ -242,7 +246,7 @@ fn test_borrow() { } #[test] -fn test_entry(){ +fn test_entry() { let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; let mut map: BTreeMap<_, _> = xs.iter().cloned().collect(); @@ -341,17 +345,23 @@ fn test_bad_zst() { struct Bad; impl PartialEq for Bad { - fn eq(&self, _: &Self) -> bool { false } + fn eq(&self, _: &Self) -> bool { + false + } } impl Eq for Bad {} impl PartialOrd for Bad { - fn partial_cmp(&self, _: &Self) -> Option { Some(Ordering::Less) } + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Less) + } } impl Ord for Bad { - fn cmp(&self, _: &Self) -> Ordering { Ordering::Less } + fn cmp(&self, _: &Self) -> Ordering { + Ordering::Less + } } let mut m = BTreeMap::new(); @@ -368,27 +378,27 @@ fn test_clone() { assert_eq!(map.len(), 0); for i in 0..size { - assert_eq!(map.insert(i, 10*i), None); + assert_eq!(map.insert(i, 10 * i), None); assert_eq!(map.len(), i + 1); assert_eq!(map, map.clone()); } for i in 0..size { - assert_eq!(map.insert(i, 100*i), Some(10*i)); + assert_eq!(map.insert(i, 100 * i), Some(10 * i)); assert_eq!(map.len(), size); assert_eq!(map, map.clone()); } - for i in 0..size/2 { - assert_eq!(map.remove(&(i*2)), Some(i*200)); + for i in 0..size / 2 { + assert_eq!(map.remove(&(i * 2)), Some(i * 200)); assert_eq!(map.len(), size - i - 1); assert_eq!(map, map.clone()); } - for i in 0..size/2 { - assert_eq!(map.remove(&(2*i)), None); - assert_eq!(map.remove(&(2*i+1)), Some(i*200 + 100)); - assert_eq!(map.len(), size/2 - i - 1); + for i in 0..size / 2 { + assert_eq!(map.remove(&(2 * i)), None); + assert_eq!(map.remove(&(2 * i + 1)), Some(i * 200 + 100)); + assert_eq!(map.len(), size / 2 - i - 1); assert_eq!(map, map.clone()); } } @@ -398,16 +408,36 @@ fn test_clone() { fn test_variance() { use std::collections::btree_map::{Iter, IntoIter, Range, Keys, Values}; - fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> { v } - fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> { v } - fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> { v } - fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> { v } - fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> { v } - fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> { v } - fn range_key<'a, 'new>(v: Range<'a, &'static str, ()>) -> Range<'a, &'new str, ()> { v } - fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> { v } - fn keys<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> { v } - fn vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> { v } + fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> { + v + } + fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> { + v + } + fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> { + v + } + fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> { + v + } + fn range_key<'a, 'new>(v: Range<'a, &'static str, ()>) -> Range<'a, &'new str, ()> { + v + } + fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> { + v + } + fn keys<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> { + v + } + fn vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> { + v + } } #[test] @@ -440,7 +470,7 @@ fn test_vacant_entry_key() { Vacant(e) => { assert_eq!(key, *e.key()); e.insert(value.clone()); - }, + } } assert_eq!(a.len(), 1); assert_eq!(a[key], value); diff --git a/src/libcollectionstest/enum_set.rs b/src/libcollectionstest/enum_set.rs index b073c2f3ae4d..0702471104bd 100644 --- a/src/libcollectionstest/enum_set.rs +++ b/src/libcollectionstest/enum_set.rs @@ -17,7 +17,9 @@ use self::Foo::*; #[derive(Copy, Clone, PartialEq, Debug)] #[repr(usize)] enum Foo { - A, B, C + A, + B, + C, } impl CLike for Foo { @@ -60,9 +62,8 @@ fn test_len() { assert_eq!(e.len(), 0); } -/////////////////////////////////////////////////////////////////////////// -// intersect - +/// //////////////////////////////////////////////////////////////////////// +/// intersect #[test] fn test_two_empties_do_not_intersect() { let e1: EnumSet = EnumSet::new(); @@ -105,9 +106,8 @@ fn test_overlapping_intersects() { assert!(!e1.is_disjoint(&e2)); } -/////////////////////////////////////////////////////////////////////////// -// contains and contains_elem - +/// //////////////////////////////////////////////////////////////////////// +/// contains and contains_elem #[test] fn test_superset() { let mut e1: EnumSet = EnumSet::new(); @@ -141,9 +141,8 @@ fn test_contains() { assert!(!e1.contains(&C)); } -/////////////////////////////////////////////////////////////////////////// -// iter - +/// //////////////////////////////////////////////////////////////////////// +/// iter #[test] fn test_iterator() { let mut e1: EnumSet = EnumSet::new(); @@ -157,20 +156,19 @@ fn test_iterator() { e1.insert(C); let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A,C]); + assert_eq!(elems, [A, C]); e1.insert(C); let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A,C]); + assert_eq!(elems, [A, C]); e1.insert(B); let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A,B,C]); + assert_eq!(elems, [A, B, C]); } -/////////////////////////////////////////////////////////////////////////// -// operators - +/// //////////////////////////////////////////////////////////////////////// +/// operators #[test] fn test_operators() { let mut e1: EnumSet = EnumSet::new(); @@ -183,7 +181,7 @@ fn test_operators() { let e_union = e1 | e2; let elems: Vec<_> = e_union.iter().collect(); - assert_eq!(elems, [A,B,C]); + assert_eq!(elems, [A, B, C]); let e_intersection = e1 & e2; let elems: Vec<_> = e_intersection.iter().collect(); @@ -201,17 +199,17 @@ fn test_operators() { // Bitwise XOR of two sets, aka symmetric difference let e_symmetric_diff = e1 ^ e2; let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A,B]); + assert_eq!(elems, [A, B]); // Another way to express symmetric difference let e_symmetric_diff = (e1 - e2) | (e2 - e1); let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A,B]); + assert_eq!(elems, [A, B]); // Yet another way to express symmetric difference let e_symmetric_diff = (e1 | e2) - (e1 & e2); let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A,B]); + assert_eq!(elems, [A, B]); } #[test] @@ -221,13 +219,76 @@ fn test_overflow() { #[derive(Copy, Clone)] #[repr(usize)] enum Bar { - V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, - V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, - V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, - V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, - V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, - V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, - V60, V61, V62, V63, V64, V65, V66, V67, V68, V69, + V00, + V01, + V02, + V03, + V04, + V05, + V06, + V07, + V08, + V09, + V10, + V11, + V12, + V13, + V14, + V15, + V16, + V17, + V18, + V19, + V20, + V21, + V22, + V23, + V24, + V25, + V26, + V27, + V28, + V29, + V30, + V31, + V32, + V33, + V34, + V35, + V36, + V37, + V38, + V39, + V40, + V41, + V42, + V43, + V44, + V45, + V46, + V47, + V48, + V49, + V50, + V51, + V52, + V53, + V54, + V55, + V56, + V57, + V58, + V59, + V60, + V61, + V62, + V63, + V64, + V65, + V66, + V67, + V68, + V69, } impl CLike for Bar { diff --git a/src/libcollectionstest/linked_list.rs b/src/libcollectionstest/linked_list.rs index 7265d53be483..956d75a95a58 100644 --- a/src/libcollectionstest/linked_list.rs +++ b/src/libcollectionstest/linked_list.rs @@ -54,7 +54,7 @@ fn test_basic() { #[cfg(test)] fn generate_test() -> LinkedList { - list_from(&[0,1,2,3,4,5,6]) + list_from(&[0, 1, 2, 3, 4, 5, 6]) } #[cfg(test)] @@ -78,7 +78,7 @@ fn test_split_off() { // not singleton, forwards { - let u = vec![1,2,3,4,5]; + let u = vec![1, 2, 3, 4, 5]; let mut m = list_from(&u); let mut n = m.split_off(2); assert_eq!(m.len(), 2); @@ -92,7 +92,7 @@ fn test_split_off() { } // not singleton, backwards { - let u = vec![1,2,3,4,5]; + let u = vec![1, 2, 3, 4, 5]; let mut m = list_from(&u); let mut n = m.split_off(4); assert_eq!(m.len(), 4); @@ -246,33 +246,33 @@ fn test_eq() { m.push_back(1); assert!(n == m); - let n = list_from(&[2,3,4]); - let m = list_from(&[1,2,3]); + let n = list_from(&[2, 3, 4]); + let m = list_from(&[1, 2, 3]); assert!(n != m); } #[test] fn test_hash() { - let mut x = LinkedList::new(); - let mut y = LinkedList::new(); + let mut x = LinkedList::new(); + let mut y = LinkedList::new(); - assert!(::hash(&x) == ::hash(&y)); + assert!(::hash(&x) == ::hash(&y)); - x.push_back(1); - x.push_back(2); - x.push_back(3); + x.push_back(1); + x.push_back(2); + x.push_back(3); - y.push_front(3); - y.push_front(2); - y.push_front(1); + y.push_front(3); + y.push_front(2); + y.push_front(1); - assert!(::hash(&x) == ::hash(&y)); + assert!(::hash(&x) == ::hash(&y)); } #[test] fn test_ord() { let n = list_from(&[]); - let m = list_from(&[1,2,3]); + let m = list_from(&[1, 2, 3]); assert!(n < m); assert!(m > n); assert!(n <= n); @@ -281,7 +281,7 @@ fn test_ord() { #[test] fn test_ord_nan() { - let nan = 0.0f64/0.0; + let nan = 0.0f64 / 0.0; let n = list_from(&[nan]); let m = list_from(&[nan]); assert!(!(n < m)); @@ -296,15 +296,15 @@ fn test_ord_nan() { assert!(!(n <= one)); assert!(!(n >= one)); - let u = list_from(&[1.0f64,2.0,nan]); - let v = list_from(&[1.0f64,2.0,3.0]); + let u = list_from(&[1.0f64, 2.0, nan]); + let v = list_from(&[1.0f64, 2.0, 3.0]); assert!(!(u < v)); assert!(!(u > v)); assert!(!(u <= v)); assert!(!(u >= v)); - let s = list_from(&[1.0f64,2.0,4.0,2.0]); - let t = list_from(&[1.0f64,2.0,3.0,2.0]); + let s = list_from(&[1.0f64, 2.0, 4.0, 2.0]); + let t = list_from(&[1.0f64, 2.0, 3.0, 2.0]); assert!(!(s < t)); assert!(s > one); assert!(!(s <= one)); @@ -317,7 +317,8 @@ fn test_show() { assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"); let list: LinkedList<_> = vec!["just", "one", "test", "more"].iter().cloned().collect(); - assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]"); + assert_eq!(format!("{:?}", list), + "[\"just\", \"one\", \"test\", \"more\"]"); } #[test] diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 236c151891d1..76d70b113f77 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -13,9 +13,13 @@ use std::mem; use std::__rand::{Rng, thread_rng}; use std::rc::Rc; -fn square(n: usize) -> usize { n * n } +fn square(n: usize) -> usize { + n * n +} -fn is_odd(n: &usize) -> bool { *n % 2 == 1 } +fn is_odd(n: &usize) -> bool { + *n % 2 == 1 +} #[test] fn test_from_fn() { @@ -76,9 +80,9 @@ fn test_is_empty() { #[test] fn test_len_divzero() { type Z = [i8; 0]; - let v0 : &[Z] = &[]; - let v1 : &[Z] = &[[]]; - let v2 : &[Z] = &[[], []]; + let v0: &[Z] = &[]; + let v1: &[Z] = &[[]]; + let v2: &[Z] = &[[], []]; assert_eq!(mem::size_of::(), 0); assert_eq!(v0.len(), 0); assert_eq!(v1.len(), 1); @@ -295,7 +299,7 @@ fn test_push() { #[test] fn test_truncate() { - let mut v: Vec> = vec![box 6,box 5,box 4]; + let mut v: Vec> = vec![box 6, box 5, box 4]; v.truncate(1); let v = v; assert_eq!(v.len(), 1); @@ -305,7 +309,7 @@ fn test_truncate() { #[test] fn test_clear() { - let mut v: Vec> = vec![box 6,box 5,box 4]; + let mut v: Vec> = vec![box 6, box 5, box 4]; v.clear(); assert_eq!(v.len(), 0); // If the unsafe block didn't drop things properly, we blow up here. @@ -320,12 +324,12 @@ fn test_dedup() { } case(vec![], vec![]); case(vec![1], vec![1]); - case(vec![1,1], vec![1]); - case(vec![1,2,3], vec![1,2,3]); - case(vec![1,1,2,3], vec![1,2,3]); - case(vec![1,2,2,3], vec![1,2,3]); - case(vec![1,2,3,3], vec![1,2,3]); - case(vec![1,1,2,2,2,3,3], vec![1,2,3]); + case(vec![1, 1], vec![1]); + case(vec![1, 2, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 3, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]); } #[test] @@ -336,10 +340,9 @@ fn test_dedup_unique() { v1.dedup(); let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; v2.dedup(); - /* - * If the boxed pointers were leaked or otherwise misused, valgrind - * and/or rt should raise errors. - */ + // If the boxed pointers were leaked or otherwise misused, valgrind + // and/or rt should raise errors. + // } #[test] @@ -350,10 +353,9 @@ fn test_dedup_shared() { v1.dedup(); let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; v2.dedup(); - /* - * If the pointers were leaked or otherwise misused, valgrind and/or - * rt should raise errors. - */ + // If the pointers were leaked or otherwise misused, valgrind and/or + // rt should raise errors. + // } #[test] @@ -365,31 +367,31 @@ fn test_retain() { #[test] fn test_binary_search() { - assert_eq!([1,2,3,4,5].binary_search(&5).ok(), Some(4)); - assert_eq!([1,2,3,4,5].binary_search(&4).ok(), Some(3)); - assert_eq!([1,2,3,4,5].binary_search(&3).ok(), Some(2)); - assert_eq!([1,2,3,4,5].binary_search(&2).ok(), Some(1)); - assert_eq!([1,2,3,4,5].binary_search(&1).ok(), Some(0)); - - assert_eq!([2,4,6,8,10].binary_search(&1).ok(), None); - assert_eq!([2,4,6,8,10].binary_search(&5).ok(), None); - assert_eq!([2,4,6,8,10].binary_search(&4).ok(), Some(1)); - assert_eq!([2,4,6,8,10].binary_search(&10).ok(), Some(4)); - - assert_eq!([2,4,6,8].binary_search(&1).ok(), None); - assert_eq!([2,4,6,8].binary_search(&5).ok(), None); - assert_eq!([2,4,6,8].binary_search(&4).ok(), Some(1)); - assert_eq!([2,4,6,8].binary_search(&8).ok(), Some(3)); - - assert_eq!([2,4,6].binary_search(&1).ok(), None); - assert_eq!([2,4,6].binary_search(&5).ok(), None); - assert_eq!([2,4,6].binary_search(&4).ok(), Some(1)); - assert_eq!([2,4,6].binary_search(&6).ok(), Some(2)); - - assert_eq!([2,4].binary_search(&1).ok(), None); - assert_eq!([2,4].binary_search(&5).ok(), None); - assert_eq!([2,4].binary_search(&2).ok(), Some(0)); - assert_eq!([2,4].binary_search(&4).ok(), Some(1)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&5).ok(), Some(4)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&4).ok(), Some(3)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&3).ok(), Some(2)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&2).ok(), Some(1)); + assert_eq!([1, 2, 3, 4, 5].binary_search(&1).ok(), Some(0)); + + assert_eq!([2, 4, 6, 8, 10].binary_search(&1).ok(), None); + assert_eq!([2, 4, 6, 8, 10].binary_search(&5).ok(), None); + assert_eq!([2, 4, 6, 8, 10].binary_search(&4).ok(), Some(1)); + assert_eq!([2, 4, 6, 8, 10].binary_search(&10).ok(), Some(4)); + + assert_eq!([2, 4, 6, 8].binary_search(&1).ok(), None); + assert_eq!([2, 4, 6, 8].binary_search(&5).ok(), None); + assert_eq!([2, 4, 6, 8].binary_search(&4).ok(), Some(1)); + assert_eq!([2, 4, 6, 8].binary_search(&8).ok(), Some(3)); + + assert_eq!([2, 4, 6].binary_search(&1).ok(), None); + assert_eq!([2, 4, 6].binary_search(&5).ok(), None); + assert_eq!([2, 4, 6].binary_search(&4).ok(), Some(1)); + assert_eq!([2, 4, 6].binary_search(&6).ok(), Some(2)); + + assert_eq!([2, 4].binary_search(&1).ok(), None); + assert_eq!([2, 4].binary_search(&5).ok(), None); + assert_eq!([2, 4].binary_search(&2).ok(), Some(0)); + assert_eq!([2, 4].binary_search(&4).ok(), Some(1)); assert_eq!([2].binary_search(&1).ok(), None); assert_eq!([2].binary_search(&5).ok(), None); @@ -398,14 +400,14 @@ fn test_binary_search() { assert_eq!([].binary_search(&1).ok(), None); assert_eq!([].binary_search(&5).ok(), None); - assert!([1,1,1,1,1].binary_search(&1).ok() != None); - assert!([1,1,1,1,2].binary_search(&1).ok() != None); - assert!([1,1,1,2,2].binary_search(&1).ok() != None); - assert!([1,1,2,2,2].binary_search(&1).ok() != None); - assert_eq!([1,2,2,2,2].binary_search(&1).ok(), Some(0)); + assert!([1, 1, 1, 1, 1].binary_search(&1).ok() != None); + assert!([1, 1, 1, 1, 2].binary_search(&1).ok() != None); + assert!([1, 1, 1, 2, 2].binary_search(&1).ok() != None); + assert!([1, 1, 2, 2, 2].binary_search(&1).ok() != None); + assert_eq!([1, 2, 2, 2, 2].binary_search(&1).ok(), Some(0)); - assert_eq!([1,2,3,4,5].binary_search(&6).ok(), None); - assert_eq!([1,2,3,4,5].binary_search(&0).ok(), None); + assert_eq!([1, 2, 3, 4, 5].binary_search(&6).ok(), None); + assert_eq!([1, 2, 3, 4, 5].binary_search(&0).ok(), None); } #[test] @@ -460,15 +462,17 @@ fn test_sort_stability() { // the second item represents which occurrence of that // number this element is, i.e. the second elements // will occur in sorted order. - let mut v: Vec<_> = (0..len).map(|_| { - let n = thread_rng().gen::() % 10; - counts[n] += 1; - (n, counts[n]) - }).collect(); + let mut v: Vec<_> = (0..len) + .map(|_| { + let n = thread_rng().gen::() % 10; + counts[n] += 1; + (n, counts[n]) + }) + .collect(); // only sort on the first element, so an unstable sort // may mix up the counts. - v.sort_by(|&(a,_), &(b,_)| a.cmp(&b)); + v.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); // this comparison includes the count (the second item // of the tuple), so elements with equal first items @@ -679,7 +683,7 @@ fn test_rev_iterator() { #[test] fn test_mut_rev_iterator() { let mut xs = [1, 2, 3, 4, 5]; - for (i,x) in xs.iter_mut().rev().enumerate() { + for (i, x) in xs.iter_mut().rev().enumerate() { *x += i; } assert!(xs == [5, 5, 5, 5, 5]) @@ -687,35 +691,32 @@ fn test_mut_rev_iterator() { #[test] fn test_move_iterator() { - let xs = vec![1,2,3,4,5]; - assert_eq!(xs.into_iter().fold(0, |a: usize, b: usize| 10*a + b), 12345); + let xs = vec![1, 2, 3, 4, 5]; + assert_eq!(xs.into_iter().fold(0, |a: usize, b: usize| 10 * a + b), + 12345); } #[test] fn test_move_rev_iterator() { - let xs = vec![1,2,3,4,5]; - assert_eq!(xs.into_iter().rev().fold(0, |a: usize, b: usize| 10*a + b), 54321); + let xs = vec![1, 2, 3, 4, 5]; + assert_eq!(xs.into_iter().rev().fold(0, |a: usize, b: usize| 10 * a + b), + 54321); } #[test] fn test_splitator() { - let xs = &[1,2,3,4,5]; + let xs = &[1, 2, 3, 4, 5]; let splits: &[&[_]] = &[&[1], &[3], &[5]]; - assert_eq!(xs.split(|x| *x % 2 == 0).collect::>(), - splits); - let splits: &[&[_]] = &[&[], &[2,3,4,5]]; - assert_eq!(xs.split(|x| *x == 1).collect::>(), - splits); - let splits: &[&[_]] = &[&[1,2,3,4], &[]]; - assert_eq!(xs.split(|x| *x == 5).collect::>(), - splits); - let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.split(|x| *x == 10).collect::>(), - splits); + assert_eq!(xs.split(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[], &[2, 3, 4, 5]]; + assert_eq!(xs.split(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[]]; + assert_eq!(xs.split(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split(|x| *x == 10).collect::>(), splits); let splits: &[&[_]] = &[&[], &[], &[], &[], &[], &[]]; - assert_eq!(xs.split(|_| true).collect::>(), - splits); + assert_eq!(xs.split(|_| true).collect::>(), splits); let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; @@ -724,17 +725,14 @@ fn test_splitator() { #[test] fn test_splitnator() { - let xs = &[1,2,3,4,5]; + let xs = &[1, 2, 3, 4, 5]; - let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), - splits); - let splits: &[&[_]] = &[&[1], &[3,4,5]]; - assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::>(), - splits); - let splits: &[&[_]] = &[&[], &[], &[], &[4,5]]; - assert_eq!(xs.splitn(4, |_| true).collect::>(), - splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[3, 4, 5]]; + assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[], &[], &[], &[4, 5]]; + assert_eq!(xs.splitn(4, |_| true).collect::>(), splits); let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; @@ -743,40 +741,34 @@ fn test_splitnator() { #[test] fn test_splitnator_mut() { - let xs = &mut [1,2,3,4,5]; + let xs = &mut [1, 2, 3, 4, 5]; - let splits: &[&mut[_]] = &[&mut [1,2,3,4,5]]; + let splits: &[&mut [_]] = &[&mut [1, 2, 3, 4, 5]]; assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&mut[_]] = &[&mut [1], &mut [3,4,5]]; + let splits: &[&mut [_]] = &[&mut [1], &mut [3, 4, 5]]; assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::>(), splits); - let splits: &[&mut[_]] = &[&mut [], &mut [], &mut [], &mut [4,5]]; - assert_eq!(xs.splitn_mut(4, |_| true).collect::>(), - splits); + let splits: &[&mut [_]] = &[&mut [], &mut [], &mut [], &mut [4, 5]]; + assert_eq!(xs.splitn_mut(4, |_| true).collect::>(), splits); let xs: &mut [i32] = &mut []; - let splits: &[&mut[i32]] = &[&mut []]; - assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::>(), - splits); + let splits: &[&mut [i32]] = &[&mut []]; + assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::>(), splits); } #[test] fn test_rsplitator() { - let xs = &[1,2,3,4,5]; + let xs = &[1, 2, 3, 4, 5]; let splits: &[&[_]] = &[&[5], &[3], &[1]]; - assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::>(), - splits); - let splits: &[&[_]] = &[&[2,3,4,5], &[]]; - assert_eq!(xs.split(|x| *x == 1).rev().collect::>(), - splits); - let splits: &[&[_]] = &[&[], &[1,2,3,4]]; - assert_eq!(xs.split(|x| *x == 5).rev().collect::>(), - splits); - let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.split(|x| *x == 10).rev().collect::>(), - splits); + assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[]]; + assert_eq!(xs.split(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[], &[1, 2, 3, 4]]; + assert_eq!(xs.split(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split(|x| *x == 10).rev().collect::>(), splits); let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; @@ -785,19 +777,16 @@ fn test_rsplitator() { #[test] fn test_rsplitnator() { - let xs = &[1,2,3,4,5]; + let xs = &[1, 2, 3, 4, 5]; - let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), - splits); - let splits: &[&[_]] = &[&[5], &[1,2,3]]; - assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::>(), - splits); - let splits: &[&[_]] = &[&[], &[], &[], &[1,2]]; - assert_eq!(xs.rsplitn(4, |_| true).collect::>(), - splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3]]; + assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[], &[], &[], &[1, 2]]; + assert_eq!(xs.rsplitn(4, |_| true).collect::>(), splits); - let xs: &[i32] = &[]; + let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::>(), splits); assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none()); @@ -805,55 +794,55 @@ fn test_rsplitnator() { #[test] fn test_windowsator() { - let v = &[1,2,3,4]; + let v = &[1, 2, 3, 4]; - let wins: &[&[_]] = &[&[1,2], &[2,3], &[3,4]]; + let wins: &[&[_]] = &[&[1, 2], &[2, 3], &[3, 4]]; assert_eq!(v.windows(2).collect::>(), wins); - let wins: &[&[_]] = &[&[1,2,3], &[2,3,4]]; + let wins: &[&[_]] = &[&[1, 2, 3], &[2, 3, 4]]; assert_eq!(v.windows(3).collect::>(), wins); assert!(v.windows(6).next().is_none()); - let wins: &[&[_]] = &[&[3,4], &[2,3], &[1,2]]; + let wins: &[&[_]] = &[&[3, 4], &[2, 3], &[1, 2]]; assert_eq!(v.windows(2).rev().collect::>(), wins); } #[test] #[should_panic] fn test_windowsator_0() { - let v = &[1,2,3,4]; + let v = &[1, 2, 3, 4]; let _it = v.windows(0); } #[test] fn test_chunksator() { - let v = &[1,2,3,4,5]; + let v = &[1, 2, 3, 4, 5]; assert_eq!(v.chunks(2).len(), 3); - let chunks: &[&[_]] = &[&[1,2], &[3,4], &[5]]; + let chunks: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; assert_eq!(v.chunks(2).collect::>(), chunks); - let chunks: &[&[_]] = &[&[1,2,3], &[4,5]]; + let chunks: &[&[_]] = &[&[1, 2, 3], &[4, 5]]; assert_eq!(v.chunks(3).collect::>(), chunks); - let chunks: &[&[_]] = &[&[1,2,3,4,5]]; + let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]]; assert_eq!(v.chunks(6).collect::>(), chunks); - let chunks: &[&[_]] = &[&[5], &[3,4], &[1,2]]; + let chunks: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; assert_eq!(v.chunks(2).rev().collect::>(), chunks); } #[test] #[should_panic] fn test_chunksator_0() { - let v = &[1,2,3,4]; + let v = &[1, 2, 3, 4]; let _it = v.chunks(0); } #[test] fn test_reverse_part() { - let mut values = [1,2,3,4,5]; + let mut values = [1, 2, 3, 4, 5]; values[1..4].reverse(); - assert!(values == [1,4,3,2,5]); + assert!(values == [1, 4, 3, 2, 5]); } #[test] @@ -869,16 +858,15 @@ fn test_show() { test_show_vec!(empty, "[]"); test_show_vec!(vec![1], "[1]"); test_show_vec!(vec![1, 2, 3], "[1, 2, 3]"); - test_show_vec!(vec![vec![], vec![1], vec![1, 1]], - "[[], [1], [1, 1]]"); + test_show_vec!(vec![vec![], vec![1], vec![1, 1]], "[[], [1], [1, 1]]"); - let empty_mut: &mut [i32] = &mut[]; + let empty_mut: &mut [i32] = &mut []; test_show_vec!(empty_mut, "[]"); - let v = &mut[1]; + let v = &mut [1]; test_show_vec!(v, "[1]"); - let v = &mut[1, 2, 3]; + let v = &mut [1, 2, 3]; test_show_vec!(v, "[1, 2, 3]"); - let v: &mut[&mut[_]] = &mut[&mut[], &mut[1], &mut[1, 1]]; + let v: &mut [&mut [_]] = &mut [&mut [], &mut [1], &mut [1, 1]]; test_show_vec!(v, "[[], [1], [1, 1]]"); } @@ -914,7 +902,7 @@ fn test_overflow_does_not_cause_segfault_managed() { #[test] fn test_mut_split_at() { - let mut values = [1,2,3,4,5]; + let mut values = [1, 2, 3, 4, 5]; { let (left, right) = values.split_at_mut(2); { @@ -1021,32 +1009,32 @@ fn test_ends_with() { #[test] fn test_mut_splitator() { - let mut xs = [0,1,0,2,3,0,0,4,5,0]; + let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0]; assert_eq!(xs.split_mut(|x| *x == 0).count(), 6); for slice in xs.split_mut(|x| *x == 0) { slice.reverse(); } - assert!(xs == [0,1,0,3,2,0,0,5,4,0]); + assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0]); - let mut xs = [0,1,0,2,3,0,0,4,5,0,6,7]; + let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0, 6, 7]; for slice in xs.split_mut(|x| *x == 0).take(5) { slice.reverse(); } - assert!(xs == [0,1,0,3,2,0,0,5,4,0,6,7]); + assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0, 6, 7]); } #[test] fn test_mut_splitator_rev() { - let mut xs = [1,2,0,3,4,0,0,5,6,0]; + let mut xs = [1, 2, 0, 3, 4, 0, 0, 5, 6, 0]; for slice in xs.split_mut(|x| *x == 0).rev().take(4) { slice.reverse(); } - assert!(xs == [1,2,0,4,3,0,0,6,5,0]); + assert!(xs == [1, 2, 0, 4, 3, 0, 0, 6, 5, 0]); } #[test] fn test_get_mut() { - let mut v = [0,1,2]; + let mut v = [0, 1, 2]; assert_eq!(v.get_mut(3), None); v.get_mut(1).map(|e| *e = 7); assert_eq!(v[1], 7); @@ -1119,7 +1107,7 @@ fn test_box_slice_clone_panics() { struct Canary { count: Arc, - panics: bool + panics: bool, } impl Drop for Canary { @@ -1130,27 +1118,37 @@ fn test_box_slice_clone_panics() { impl Clone for Canary { fn clone(&self) -> Self { - if self.panics { panic!() } + if self.panics { + panic!() + } Canary { count: self.count.clone(), - panics: self.panics + panics: self.panics, } } } let drop_count = Arc::new(AtomicUsize::new(0)); - let canary = Canary { count: drop_count.clone(), panics: false }; - let panic = Canary { count: drop_count.clone(), panics: true }; + let canary = Canary { + count: drop_count.clone(), + panics: false, + }; + let panic = Canary { + count: drop_count.clone(), + panics: true, + }; spawn(move || { // When xs is dropped, +5. - let xs = vec![canary.clone(), canary.clone(), canary.clone(), - panic, canary].into_boxed_slice(); + let xs = vec![canary.clone(), canary.clone(), canary.clone(), panic, canary] + .into_boxed_slice(); // When panic is cloned, +3. xs.clone(); - }).join().unwrap_err(); + }) + .join() + .unwrap_err(); // Total = 8 assert_eq!(drop_count.load(Ordering::SeqCst), 8); @@ -1198,7 +1196,9 @@ mod bench { sum += *x; } // sum == 11806, to stop dead code elimination. - if sum == 0 {panic!()} + if sum == 0 { + panic!() + } }) } @@ -1217,8 +1217,7 @@ mod bench { #[bench] fn concat(b: &mut Bencher) { - let xss: Vec> = - (0..100).map(|i| (0..i).collect()).collect(); + let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); b.iter(|| { xss.concat(); }); @@ -1226,11 +1225,8 @@ mod bench { #[bench] fn join(b: &mut Bencher) { - let xss: Vec> = - (0..100).map(|i| (0..i).collect()).collect(); - b.iter(|| { - xss.join(&0) - }); + let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); + b.iter(|| xss.join(&0)); } #[bench] @@ -1245,17 +1241,13 @@ mod bench { #[bench] fn starts_with_same_vector(b: &mut Bencher) { let vec: Vec<_> = (0..100).collect(); - b.iter(|| { - vec.starts_with(&vec) - }) + b.iter(|| vec.starts_with(&vec)) } #[bench] fn starts_with_single_element(b: &mut Bencher) { let vec: Vec<_> = vec![0]; - b.iter(|| { - vec.starts_with(&vec) - }) + b.iter(|| vec.starts_with(&vec)) } #[bench] @@ -1263,25 +1255,19 @@ mod bench { let vec: Vec<_> = (0..100).collect(); let mut match_vec: Vec<_> = (0..99).collect(); match_vec.push(0); - b.iter(|| { - vec.starts_with(&match_vec) - }) + b.iter(|| vec.starts_with(&match_vec)) } #[bench] fn ends_with_same_vector(b: &mut Bencher) { let vec: Vec<_> = (0..100).collect(); - b.iter(|| { - vec.ends_with(&vec) - }) + b.iter(|| vec.ends_with(&vec)) } #[bench] fn ends_with_single_element(b: &mut Bencher) { let vec: Vec<_> = vec![0]; - b.iter(|| { - vec.ends_with(&vec) - }) + b.iter(|| vec.ends_with(&vec)) } #[bench] @@ -1289,24 +1275,18 @@ mod bench { let vec: Vec<_> = (0..100).collect(); let mut match_vec: Vec<_> = (0..100).collect(); match_vec[0] = 200; - b.iter(|| { - vec.starts_with(&match_vec) - }) + b.iter(|| vec.starts_with(&match_vec)) } #[bench] fn contains_last_element(b: &mut Bencher) { let vec: Vec<_> = (0..100).collect(); - b.iter(|| { - vec.contains(&99) - }) + b.iter(|| vec.contains(&99)) } #[bench] fn zero_1kb_from_elem(b: &mut Bencher) { - b.iter(|| { - vec![0u8; 1024] - }); + b.iter(|| vec![0u8; 1024]); } #[bench] @@ -1356,8 +1336,7 @@ mod bench { let mut v = vec![(0, 0); 30]; for _ in 0..100 { let l = v.len(); - v.insert(rng.gen::() % (l + 1), - (1, 1)); + v.insert(rng.gen::() % (l + 1), (1, 1)); } }) } @@ -1418,7 +1397,8 @@ mod bench { fn sort_big_random_small(b: &mut Bencher) { let mut rng = thread_rng(); b.iter(|| { - let mut v = rng.gen_iter::().take(5) + let mut v = rng.gen_iter::() + .take(5) .collect::>(); v.sort(); }); @@ -1429,7 +1409,8 @@ mod bench { fn sort_big_random_medium(b: &mut Bencher) { let mut rng = thread_rng(); b.iter(|| { - let mut v = rng.gen_iter::().take(100) + let mut v = rng.gen_iter::() + .take(100) .collect::>(); v.sort(); }); @@ -1440,7 +1421,8 @@ mod bench { fn sort_big_random_large(b: &mut Bencher) { let mut rng = thread_rng(); b.iter(|| { - let mut v = rng.gen_iter::().take(10000) + let mut v = rng.gen_iter::() + .take(10000) .collect::>(); v.sort(); }); diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index c2eafa1b90f1..7f0fd282ae5e 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -31,8 +31,8 @@ impl<'a> IntoCow<'a, str> for &'a str { #[test] fn test_from_str() { - let owned: Option<::std::string::String> = "string".parse().ok(); - assert_eq!(owned.as_ref().map(|s| &**s), Some("string")); + let owned: Option<::std::string::String> = "string".parse().ok(); + assert_eq!(owned.as_ref().map(|s| &**s), Some("string")); } #[test] @@ -44,8 +44,7 @@ fn test_unsized_to_string() { #[test] fn test_from_utf8() { let xs = b"hello".to_vec(); - assert_eq!(String::from_utf8(xs).unwrap(), - String::from("hello")); + assert_eq!(String::from_utf8(xs).unwrap(), String::from("hello")); let xs = "ศไทย中华Việt Nam".as_bytes().to_vec(); assert_eq!(String::from_utf8(xs).unwrap(), @@ -87,56 +86,40 @@ fn test_from_utf8_lossy() { String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow()); let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar"; - assert_eq!(String::from_utf8_lossy(xs), String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\ - foo\u{10000}bar").into_cow()); + assert_eq!(String::from_utf8_lossy(xs), + String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar").into_cow()); // surrogates let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar"; - assert_eq!(String::from_utf8_lossy(xs), String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\ - \u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow()); + assert_eq!(String::from_utf8_lossy(xs), + String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow()); } #[test] fn test_from_utf16() { - let pairs = - [(String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"), - vec![0xd800, 0xdf45, 0xd800, 0xdf3f, - 0xd800, 0xdf3b, 0xd800, 0xdf46, - 0xd800, 0xdf39, 0xd800, 0xdf3b, - 0xd800, 0xdf30, 0x000a]), - - (String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"), - vec![0xd801, 0xdc12, 0xd801, - 0xdc49, 0xd801, 0xdc2e, 0xd801, - 0xdc40, 0xd801, 0xdc32, 0xd801, - 0xdc4b, 0x0020, 0xd801, 0xdc0f, - 0xd801, 0xdc32, 0xd801, 0xdc4d, - 0x000a]), - - (String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"), - vec![0xd800, 0xdf00, 0xd800, 0xdf16, - 0xd800, 0xdf0b, 0xd800, 0xdf04, - 0xd800, 0xdf11, 0xd800, 0xdf09, - 0x00b7, 0xd800, 0xdf0c, 0xd800, - 0xdf04, 0xd800, 0xdf15, 0xd800, - 0xdf04, 0xd800, 0xdf0b, 0xd800, - 0xdf09, 0xd800, 0xdf11, 0x000a ]), - - (String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"), - vec![0xd801, 0xdc8b, 0xd801, 0xdc98, - 0xd801, 0xdc88, 0xd801, 0xdc91, - 0xd801, 0xdc9b, 0xd801, 0xdc92, - 0x0020, 0xd801, 0xdc95, 0xd801, - 0xdc93, 0x0020, 0xd801, 0xdc88, - 0xd801, 0xdc9a, 0xd801, 0xdc8d, - 0x0020, 0xd801, 0xdc8f, 0xd801, - 0xdc9c, 0xd801, 0xdc92, 0xd801, - 0xdc96, 0xd801, 0xdc86, 0x0020, - 0xd801, 0xdc95, 0xd801, 0xdc86, - 0x000a ]), - // Issue #12318, even-numbered non-BMP planes - (String::from("\u{20000}"), - vec![0xD840, 0xDC00])]; + let pairs = [(String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"), + vec![0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, + 0xdf39, 0xd800, 0xdf3b, 0xd800, 0xdf30, 0x000a]), + + (String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"), + vec![0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, + 0xdc32, 0xd801, 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, + 0xdc4d, 0x000a]), + + (String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"), + vec![0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, + 0xdf11, 0xd800, 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, + 0xdf15, 0xd800, 0xdf04, 0xd800, 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, + 0x000a]), + + (String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"), + vec![0xd801, 0xdc8b, 0xd801, 0xdc98, 0xd801, 0xdc88, 0xd801, 0xdc91, 0xd801, + 0xdc9b, 0xd801, 0xdc92, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc93, 0x0020, + 0xd801, 0xdc88, 0xd801, 0xdc9a, 0xd801, 0xdc8d, 0x0020, 0xd801, 0xdc8f, + 0xd801, 0xdc9c, 0xd801, 0xdc92, 0xd801, 0xdc96, 0xd801, 0xdc86, 0x0020, + 0xd801, 0xdc95, 0xd801, 0xdc86, 0x000a]), + // Issue #12318, even-numbered non-BMP planes + (String::from("\u{20000}"), vec![0xD840, 0xDC00])]; for p in &pairs { let (s, u) = (*p).clone(); @@ -173,13 +156,15 @@ fn test_utf16_invalid() { fn test_from_utf16_lossy() { // completely positive cases tested above. // lead + eof - assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}")); + assert_eq!(String::from_utf16_lossy(&[0xD800]), + String::from("\u{FFFD}")); // lead + lead assert_eq!(String::from_utf16_lossy(&[0xD800, 0xD800]), String::from("\u{FFFD}\u{FFFD}")); // isolated trail - assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}")); + assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), + String::from("a\u{FFFD}")); // general assert_eq!(String::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]), @@ -288,7 +273,8 @@ fn remove() { assert_eq!(s, "ไทย中华Vit Nam; foobar"); } -#[test] #[should_panic] +#[test] +#[should_panic] fn remove_bad() { "ศ".to_string().remove(1); } @@ -302,8 +288,16 @@ fn insert() { assert_eq!(s, "ệfooยbar"); } -#[test] #[should_panic] fn insert_bad1() { "".to_string().insert(1, 't'); } -#[test] #[should_panic] fn insert_bad2() { "ệ".to_string().insert(1, 't'); } +#[test] +#[should_panic] +fn insert_bad1() { + "".to_string().insert(1, 't'); +} +#[test] +#[should_panic] +fn insert_bad2() { + "ệ".to_string().insert(1, 't'); +} #[test] fn test_slicing() { @@ -331,8 +325,7 @@ fn test_vectors() { assert_eq!(format!("{:?}", x), "[]"); assert_eq!(format!("{:?}", vec![1]), "[1]"); assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]"); - assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == - "[[], [1], [1, 1]]"); + assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]"); } #[test] @@ -390,9 +383,7 @@ fn test_into_boxed_str() { #[bench] fn bench_with_capacity(b: &mut Bencher) { - b.iter(|| { - String::with_capacity(100) - }); + b.iter(|| String::with_capacity(100)); } #[bench] @@ -495,25 +486,19 @@ fn bench_exact_size_shrink_to_fit(b: &mut Bencher) { fn bench_from_str(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| { - String::from(s) - }) + b.iter(|| String::from(s)) } #[bench] fn bench_from(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| { - String::from(s) - }) + b.iter(|| String::from(s)) } #[bench] fn bench_to_string(b: &mut Bencher) { let s = "Hello there, the quick brown fox jumped over the lazy dog! \ Lorem ipsum dolor sit amet, consectetur. "; - b.iter(|| { - s.to_string() - }) + b.iter(|| s.to_string()) } diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 0fb00543ddd9..cb99659cc0ea 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -15,7 +15,7 @@ use std::mem::size_of; use test::Bencher; struct DropCounter<'a> { - count: &'a mut u32 + count: &'a mut u32, } impl<'a> Drop for DropCounter<'a> { @@ -33,17 +33,17 @@ fn test_small_vec_struct() { fn test_double_drop() { struct TwoVec { x: Vec, - y: Vec + y: Vec, } let (mut count_x, mut count_y) = (0, 0); { let mut tv = TwoVec { x: Vec::new(), - y: Vec::new() + y: Vec::new(), }; - tv.x.push(DropCounter {count: &mut count_x}); - tv.y.push(DropCounter {count: &mut count_y}); + tv.x.push(DropCounter { count: &mut count_x }); + tv.y.push(DropCounter { count: &mut count_y }); // If Vec had a drop flag, here is where it would be zeroed. // Instead, it should rely on its internal state to prevent @@ -85,12 +85,16 @@ fn test_extend() { let mut w = Vec::new(); v.extend(0..3); - for i in 0..3 { w.push(i) } + for i in 0..3 { + w.push(i) + } assert_eq!(v, w); v.extend(3..10); - for i in 3..10 { w.push(i) } + for i in 3..10 { + w.push(i) + } assert_eq!(v, w); @@ -117,7 +121,7 @@ fn test_extend_ref() { fn test_slice_from_mut() { let mut values = vec![1, 2, 3, 4, 5]; { - let slice = &mut values[2 ..]; + let slice = &mut values[2..]; assert!(slice == [3, 4, 5]); for p in slice { *p += 2; @@ -131,7 +135,7 @@ fn test_slice_from_mut() { fn test_slice_to_mut() { let mut values = vec![1, 2, 3, 4, 5]; { - let slice = &mut values[.. 2]; + let slice = &mut values[..2]; assert!(slice == [1, 2]); for p in slice { *p += 1; @@ -169,7 +173,7 @@ fn test_split_at_mut() { #[test] fn test_clone() { let v: Vec = vec![]; - let w = vec!(1, 2, 3); + let w = vec![1, 2, 3]; assert_eq!(v, v.clone()); @@ -181,9 +185,9 @@ fn test_clone() { #[test] fn test_clone_from() { - let mut v = vec!(); - let three: Vec> = vec!(box 1, box 2, box 3); - let two: Vec> = vec!(box 4, box 5); + let mut v = vec![]; + let three: Vec> = vec![box 1, box 2, box 3]; + let two: Vec> = vec![box 4, box 5]; // zero, long v.clone_from(&three); assert_eq!(v, three); @@ -235,16 +239,22 @@ fn zero_sized_values() { assert_eq!(v.iter_mut().count(), 4); for &mut () in &mut v {} - unsafe { v.set_len(0); } + unsafe { + v.set_len(0); + } assert_eq!(v.iter_mut().count(), 0); } #[test] fn test_partition() { - assert_eq!(vec![].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![])); - assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![])); - assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3])); - assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3])); + assert_eq!(vec![].into_iter().partition(|x: &i32| *x < 3), + (vec![], vec![])); + assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 4), + (vec![1, 2, 3], vec![])); + assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 2), + (vec![1], vec![2, 3])); + assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 0), + (vec![], vec![1, 2, 3])); } #[test] @@ -264,7 +274,9 @@ fn test_vec_truncate_drop() { struct Elem(i32); impl Drop for Elem { fn drop(&mut self) { - unsafe { drops += 1; } + unsafe { + drops += 1; + } } } @@ -344,7 +356,7 @@ fn test_slice_out_of_bounds_5() { #[test] #[should_panic] fn test_swap_remove_empty() { - let mut vec= Vec::::new(); + let mut vec = Vec::::new(); vec.swap_remove(0); } @@ -386,7 +398,7 @@ fn test_drain_items() { vec2.push(i); } assert_eq!(vec, []); - assert_eq!(vec2, [ 1, 2, 3 ]); + assert_eq!(vec2, [1, 2, 3]); } #[test] @@ -472,7 +484,7 @@ fn test_into_iter_count() { #[test] fn test_into_iter_clone() { - fn iter_equal>(it: I, slice: &[i32]) { + fn iter_equal>(it: I, slice: &[i32]) { let v: Vec = it.collect(); assert_eq!(&v[..], slice); } diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 05af9bd704dc..a02666a50c22 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -52,7 +52,7 @@ fn test_simple() { } #[cfg(test)] -fn test_parameterized(a: T, b: T, c: T, d: T) { +fn test_parameterized(a: T, b: T, c: T, d: T) { let mut deq = VecDeque::new(); assert_eq!(deq.len(), 0); deq.push_front(a.clone()); @@ -186,7 +186,7 @@ enum Taggypar { struct RecCy { x: i32, y: i32, - t: Taggy + t: Taggy, } #[test] @@ -209,10 +209,26 @@ fn test_param_taggypar() { #[test] fn test_param_reccy() { - let reccy1 = RecCy { x: 1, y: 2, t: One(1) }; - let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) }; - let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) }; - let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) }; + let reccy1 = RecCy { + x: 1, + y: 2, + t: One(1), + }; + let reccy2 = RecCy { + x: 345, + y: 2, + t: Two(1, 2), + }; + let reccy3 = RecCy { + x: 1, + y: 777, + t: Three(1, 2, 3), + }; + let reccy4 = RecCy { + x: 19, + y: 252, + t: Two(17, 42), + }; test_parameterized::(reccy1, reccy2, reccy3, reccy4); } @@ -257,13 +273,13 @@ fn test_with_capacity_non_power_two() { // underlying Vec which didn't hold and lead // to corruption. // (Vec grows to next power of two) - //good- [9, 12, 15, X, X, X, X, |6] - //bug- [15, 12, X, X, X, |6, X, X] + // good- [9, 12, 15, X, X, X, X, |6] + // bug- [15, 12, X, X, X, |6, X, X] assert_eq!(d3.pop_front(), Some(6)); // Which leads us to the following state which // would be a failure case. - //bug- [15, 12, X, X, X, X, |X, X] + // bug- [15, 12, X, X, X, X, |X, X] assert_eq!(d3.front(), Some(&9)); } @@ -301,7 +317,7 @@ fn test_iter() { d.push_back(i); } { - let b: &[_] = &[&0,&1,&2,&3,&4]; + let b: &[_] = &[&0, &1, &2, &3, &4]; assert_eq!(d.iter().collect::>(), b); } @@ -309,7 +325,7 @@ fn test_iter() { d.push_front(i); } { - let b: &[_] = &[&8,&7,&6,&0,&1,&2,&3,&4]; + let b: &[_] = &[&8, &7, &6, &0, &1, &2, &3, &4]; assert_eq!(d.iter().collect::>(), b); } @@ -318,7 +334,10 @@ fn test_iter() { loop { match it.next() { None => break, - _ => { len -= 1; assert_eq!(it.size_hint(), (len, Some(len))) } + _ => { + len -= 1; + assert_eq!(it.size_hint(), (len, Some(len))) + } } } } @@ -332,14 +351,14 @@ fn test_rev_iter() { d.push_back(i); } { - let b: &[_] = &[&4,&3,&2,&1,&0]; + let b: &[_] = &[&4, &3, &2, &1, &0]; assert_eq!(d.iter().rev().collect::>(), b); } for i in 6..9 { d.push_front(i); } - let b: &[_] = &[&4,&3,&2,&1,&0,&6,&7,&8]; + let b: &[_] = &[&4, &3, &2, &1, &0, &6, &7, &8]; assert_eq!(d.iter().rev().collect::>(), b); } @@ -424,7 +443,7 @@ fn test_into_iter() { d.push_back(i); } - let b = vec![0,1,2,3,4]; + let b = vec![0, 1, 2, 3, 4]; assert_eq!(d.into_iter().collect::>(), b); } @@ -438,7 +457,7 @@ fn test_into_iter() { d.push_front(i); } - let b = vec![8,7,6,0,1,2,3,4]; + let b = vec![8, 7, 6, 0, 1, 2, 3, 4]; assert_eq!(d.into_iter().collect::>(), b); } @@ -502,7 +521,7 @@ fn test_drain() { d.push_front(i); } - assert_eq!(d.drain(..).collect::>(), [8,7,6,0,1,2,3,4]); + assert_eq!(d.drain(..).collect::>(), [8, 7, 6, 0, 1, 2, 3, 4]); assert!(d.is_empty()); } @@ -532,7 +551,7 @@ fn test_drain() { #[test] fn test_from_iter() { - let v = vec!(1,2,3,4,5,6,7); + let v = vec![1, 2, 3, 4, 5, 6, 7]; let deq: VecDeque<_> = v.iter().cloned().collect(); let u: Vec<_> = deq.iter().cloned().collect(); assert_eq!(u, v); @@ -540,7 +559,7 @@ fn test_from_iter() { let seq = (0..).step_by(2).take(256); let deq: VecDeque<_> = seq.collect(); for (i, &x) in deq.iter().enumerate() { - assert_eq!(2*i, x); + assert_eq!(2 * i, x); } assert_eq!(deq.len(), 256); } @@ -585,20 +604,20 @@ fn test_eq() { #[test] fn test_hash() { - let mut x = VecDeque::new(); - let mut y = VecDeque::new(); + let mut x = VecDeque::new(); + let mut y = VecDeque::new(); - x.push_back(1); - x.push_back(2); - x.push_back(3); + x.push_back(1); + x.push_back(2); + x.push_back(3); - y.push_back(0); - y.push_back(1); - y.pop_front(); - y.push_back(2); - y.push_back(3); + y.push_back(0); + y.push_back(1); + y.pop_front(); + y.push_back(2); + y.push_back(3); - assert!(::hash(&x) == ::hash(&y)); + assert!(::hash(&x) == ::hash(&y)); } #[test] @@ -665,10 +684,12 @@ fn test_show() { let ringbuf: VecDeque<_> = (0..10).collect(); assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"); - let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter() - .cloned() - .collect(); - assert_eq!(format!("{:?}", ringbuf), "[\"just\", \"one\", \"test\", \"more\"]"); + let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"] + .iter() + .cloned() + .collect(); + assert_eq!(format!("{:?}", ringbuf), + "[\"just\", \"one\", \"test\", \"more\"]"); } #[test] @@ -677,7 +698,9 @@ fn test_drop() { struct Elem; impl Drop for Elem { fn drop(&mut self) { - unsafe { drops += 1; } + unsafe { + drops += 1; + } } } @@ -688,7 +711,7 @@ fn test_drop() { ring.push_front(Elem); drop(ring); - assert_eq!(unsafe {drops}, 4); + assert_eq!(unsafe { drops }, 4); } #[test] @@ -697,7 +720,9 @@ fn test_drop_with_pop() { struct Elem; impl Drop for Elem { fn drop(&mut self) { - unsafe { drops += 1; } + unsafe { + drops += 1; + } } } @@ -709,10 +734,10 @@ fn test_drop_with_pop() { drop(ring.pop_back()); drop(ring.pop_front()); - assert_eq!(unsafe {drops}, 2); + assert_eq!(unsafe { drops }, 2); drop(ring); - assert_eq!(unsafe {drops}, 4); + assert_eq!(unsafe { drops }, 4); } #[test] @@ -721,7 +746,9 @@ fn test_drop_clear() { struct Elem; impl Drop for Elem { fn drop(&mut self) { - unsafe { drops += 1; } + unsafe { + drops += 1; + } } } @@ -731,10 +758,10 @@ fn test_drop_clear() { ring.push_back(Elem); ring.push_front(Elem); ring.clear(); - assert_eq!(unsafe {drops}, 4); + assert_eq!(unsafe { drops }, 4); drop(ring); - assert_eq!(unsafe {drops}, 4); + assert_eq!(unsafe { drops }, 4); } #[test] @@ -822,7 +849,7 @@ fn test_get_mut() { match ring.get_mut(1) { Some(x) => *x = -1, - None => () + None => (), }; assert_eq!(ring.get_mut(0), Some(&mut 0)); @@ -852,13 +879,13 @@ fn test_front() { fn test_as_slices() { let mut ring: VecDeque = VecDeque::with_capacity(127); let cap = ring.capacity() as i32; - let first = cap/2; - let last = cap - first; + let first = cap / 2; + let last = cap - first; for i in 0..first { ring.push_back(i); let (left, right) = ring.as_slices(); - let expected: Vec<_> = (0..i+1).collect(); + let expected: Vec<_> = (0..i + 1).collect(); assert_eq!(left, &expected[..]); assert_eq!(right, []); } @@ -866,7 +893,7 @@ fn test_as_slices() { for j in -last..0 { ring.push_front(j); let (left, right) = ring.as_slices(); - let expected_left: Vec<_> = (-last..j+1).rev().collect(); + let expected_left: Vec<_> = (-last..j + 1).rev().collect(); let expected_right: Vec<_> = (0..first).collect(); assert_eq!(left, &expected_left[..]); assert_eq!(right, &expected_right[..]); @@ -880,13 +907,13 @@ fn test_as_slices() { fn test_as_mut_slices() { let mut ring: VecDeque = VecDeque::with_capacity(127); let cap = ring.capacity() as i32; - let first = cap/2; - let last = cap - first; + let first = cap / 2; + let last = cap - first; for i in 0..first { ring.push_back(i); let (left, right) = ring.as_mut_slices(); - let expected: Vec<_> = (0..i+1).collect(); + let expected: Vec<_> = (0..i + 1).collect(); assert_eq!(left, &expected[..]); assert_eq!(right, []); } @@ -894,7 +921,7 @@ fn test_as_mut_slices() { for j in -last..0 { ring.push_front(j); let (left, right) = ring.as_mut_slices(); - let expected_left: Vec<_> = (-last..j+1).rev().collect(); + let expected_left: Vec<_> = (-last..j + 1).rev().collect(); let expected_right: Vec<_> = (0..first).collect(); assert_eq!(left, &expected_left[..]); assert_eq!(right, &expected_right[..]); From 77ab6415ac54dc9138d7d6a846b30d896ec74782 Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Sun, 22 May 2016 12:47:53 -0700 Subject: [PATCH 056/179] Changed toggle all sections key to `T` Allows both `T` and `t`. It had been [Shift]+[+] before. --- src/librustdoc/html/layout.rs | 2 +- src/librustdoc/html/static/main.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 265ed6be1552..0af64573926d 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -103,7 +103,7 @@ r##"
Move down in search results
Go to active search result
-
+
+
T
Collapse/expand all sections
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 0ec5cab78bc7..e8f23c4709d4 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -124,7 +124,8 @@ focusSearchBar(); break; - case "+": + case "t": + case "T": toggleAllDocs(); break; From 68753ae23adb077ad92a0ac043badb3a347668fd Mon Sep 17 00:00:00 2001 From: Daniel Firth Date: Sun, 22 May 2016 20:47:59 +0100 Subject: [PATCH 057/179] Fix misleading intentation errors on gcc 6.0 --- src/rt/miniz.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/rt/miniz.c b/src/rt/miniz.c index 2b803b06d099..2daca9378a4a 100644 --- a/src/rt/miniz.c +++ b/src/rt/miniz.c @@ -575,7 +575,10 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex { mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + for ( i = 0; i <= 143; ++i) *p++ = 8; + for ( ; i <= 255; ++i) *p++ = 9; + for ( ; i <= 279; ++i) *p++ = 7; + for ( ; i <= 287; ++i) *p++ = 8; } else { @@ -1393,7 +1396,10 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } - if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; + if (!dist) break; + p = s; q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) break; if (probe_len > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; From d1e2de87ae62cdd95316bc701ccbf4595aa2f481 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 23 May 2016 10:23:36 +1200 Subject: [PATCH 058/179] save-analysis: use a function's short name --- src/librustc_save_analysis/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8c00a5699939..7dba3ef5c67c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -123,15 +123,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { - let name = self.tcx.node_path_str(item.id); - let qualname = format!("::{}", name); + let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); filter!(self.span_utils, sub_span, item.span, None); Some(Data::FunctionData(FunctionData { id: item.id, - name: name, + name: item.ident.to_string(), qualname: qualname, declaration: None, span: sub_span.unwrap(), From cecdd90495fb0e2cbbca1fff05e163944bab27d4 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 13 May 2016 17:17:10 +0200 Subject: [PATCH 059/179] Don't suggest using fields in a static method --- src/librustc_resolve/lib.rs | 86 ++++++++++++++----- src/test/compile-fail/issue-2356.rs | 7 +- .../unresolved_static_type_field.rs | 24 ++++++ 3 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 src/test/compile-fail/unresolved_static_type_field.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 61ed88ec173d..41cc54628164 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -67,7 +67,7 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Pat, PatKind, Path}; -use syntax::ast::{PathSegment, PathParameters, TraitItemKind, TraitRef, Ty, TyKind}; +use syntax::ast::{PathSegment, PathParameters, SelfKind, TraitItemKind, TraitRef, Ty, TyKind}; use std::collections::{HashMap, HashSet}; use std::cell::{Cell, RefCell}; @@ -148,7 +148,13 @@ enum ResolutionError<'a> { /// error E0424: `self` is not available in a static method SelfNotAvailableInStaticMethod, /// error E0425: unresolved name - UnresolvedName(&'a str, &'a str, UnresolvedNameContext<'a>), + UnresolvedName { + path: &'a str, + message: &'a str, + context: UnresolvedNameContext<'a>, + is_static_method: bool, + is_field: bool + }, /// error E0426: use of undeclared label UndeclaredLabel(&'a str), /// error E0427: cannot use `ref` binding mode with ... @@ -406,16 +412,21 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "`self` is not available in a static method. Maybe a `self` \ argument is missing?") } - ResolutionError::UnresolvedName(path, msg, context) => { + ResolutionError::UnresolvedName { path, message: msg, context, is_static_method, + is_field } => { let mut err = struct_span_err!(resolver.session, span, E0425, "unresolved name `{}`{}", path, msg); - match context { - UnresolvedNameContext::Other => { } // no help available + UnresolvedNameContext::Other => { + if msg.is_empty() && is_static_method && is_field { + err.help("this is an associated function, you don't have access to \ + this type's fields or methods"); + } + } UnresolvedNameContext::PathIsMod(parent) => { err.help(&match parent.map(|parent| &parent.node) { Some(&ExprKind::Field(_, ident)) => { @@ -596,7 +607,7 @@ impl<'a, 'v> Visitor<'v> for Resolver<'a> { } FnKind::Method(_, sig, _) => { self.visit_generics(&sig.generics); - MethodRibKind + MethodRibKind(sig.explicit_self.node == SelfKind::Static) } FnKind::Closure => ClosureRibKind(node_id), }; @@ -666,7 +677,9 @@ enum RibKind<'a> { // methods. Allow references to ty params that impl or trait // binds. Disallow any other upvars (including other ty params that are // upvars). - MethodRibKind, + // + // The boolean value represents the fact that this method is static or not. + MethodRibKind(bool), // We passed through an item scope. Disallow upvars. ItemRibKind, @@ -1095,7 +1108,13 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { Err(false) => { let path_name = &format!("{}", path); let error = - ResolutionError::UnresolvedName(path_name, "", UnresolvedNameContext::Other); + ResolutionError::UnresolvedName { + path: path_name, + message: "", + context: UnresolvedNameContext::Other, + is_static_method: false, + is_field: false + }; resolve_error(self, path.span, error); Def::Err } @@ -1657,7 +1676,9 @@ impl<'a> Resolver<'a> { let type_parameters = HasTypeParameters(&sig.generics, FnSpace, - MethodRibKind); + MethodRibKind( + sig.explicit_self.node == + SelfKind::Static)); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_trait_item(this, trait_item) }); @@ -1776,7 +1797,10 @@ impl<'a> Resolver<'a> { self.value_ribs.pop(); } - fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) { + fn resolve_function(&mut self, + rib_kind: RibKind<'a>, + declaration: &FnDecl, + block: &Block) { // Create a value rib for the function. self.value_ribs.push(Rib::new(rib_kind)); @@ -1983,7 +2007,9 @@ impl<'a> Resolver<'a> { let type_parameters = HasTypeParameters(&sig.generics, FnSpace, - MethodRibKind); + MethodRibKind( + sig.explicit_self.node == + SelfKind::Static)); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_impl_item(this, impl_item); }); @@ -2677,7 +2703,7 @@ impl<'a> Resolver<'a> { def = Def::Upvar(node_def_id, node_id, depth, function_id); seen.insert(node_id, depth); } - ItemRibKind | MethodRibKind => { + ItemRibKind | MethodRibKind(_) => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -2699,7 +2725,7 @@ impl<'a> Resolver<'a> { Def::TyParam(..) | Def::SelfTy(..) => { for rib in ribs { match rib.kind { - NormalRibKind | MethodRibKind | ClosureRibKind(..) | + NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) | ModuleRibKind(..) => { // Nothing to do. Continue. } @@ -2992,9 +3018,13 @@ impl<'a> Resolver<'a> { // `resolve_path` already reported the error } else { let mut method_scope = false; + let mut is_static = false; self.value_ribs.iter().rev().all(|rib| { method_scope = match rib.kind { - MethodRibKind => true, + MethodRibKind(is_static_) => { + is_static = is_static_; + true + } ItemRibKind | ConstantItemRibKind => false, _ => return true, // Keep advancing }; @@ -3008,22 +3038,29 @@ impl<'a> Resolver<'a> { ResolutionError::SelfNotAvailableInStaticMethod); } else { let last_name = path.segments.last().unwrap().identifier.name; - let mut msg = match self.find_fallback_in_self_type(last_name) { + let (mut msg, is_field) = + match self.find_fallback_in_self_type(last_name) { NoSuggestion => { // limit search to 5 to reduce the number // of stupid suggestions - match self.find_best_match(&path_name) { + (match self.find_best_match(&path_name) { SuggestionType::Macro(s) => { format!("the macro `{}`", s) } SuggestionType::Function(s) => format!("`{}`", s), SuggestionType::NotFound => "".to_string(), - } + }, false) + } + Field => { + (if is_static && method_scope { + "".to_string() + } else { + format!("`self.{}`", path_name) + }, true) } - Field => format!("`self.{}`", path_name), - TraitItem => format!("to call `self.{}`", path_name), + TraitItem => (format!("to call `self.{}`", path_name), false), TraitMethod(path_str) => - format!("to call `{}::{}`", path_str, path_name), + (format!("to call `{}::{}`", path_str, path_name), false), }; let mut context = UnresolvedNameContext::Other; @@ -3048,8 +3085,13 @@ impl<'a> Resolver<'a> { resolve_error(self, expr.span, - ResolutionError::UnresolvedName( - &path_name, &msg, context)); + ResolutionError::UnresolvedName { + path: &path_name, + message: &msg, + context: context, + is_static_method: method_scope && is_static, + is_field: is_field, + }); } } } diff --git a/src/test/compile-fail/issue-2356.rs b/src/test/compile-fail/issue-2356.rs index 6b81afe13c67..5e816bcfa61e 100644 --- a/src/test/compile-fail/issue-2356.rs +++ b/src/test/compile-fail/issue-2356.rs @@ -32,7 +32,8 @@ impl MaybeDog { impl Groom for cat { fn shave(other: usize) { whiskers -= other; - //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`? + //~^ ERROR: unresolved name `whiskers` + //~| HELP this is an associated function shave(4); //~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`? purr(); @@ -77,7 +78,8 @@ impl cat { pub fn grow_older(other:usize) { whiskers = 4; - //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`? + //~^ ERROR: unresolved name `whiskers` + //~| HELP this is an associated function purr_louder(); //~^ ERROR: unresolved name `purr_louder` } @@ -86,5 +88,6 @@ impl cat { fn main() { self += 1; //~^ ERROR: unresolved name `self` + //~| HELP: Module // it's a bug if this suggests a missing `self` as we're not in a method } diff --git a/src/test/compile-fail/unresolved_static_type_field.rs b/src/test/compile-fail/unresolved_static_type_field.rs new file mode 100644 index 000000000000..80f6108f02d3 --- /dev/null +++ b/src/test/compile-fail/unresolved_static_type_field.rs @@ -0,0 +1,24 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f(_: bool) {} + +struct Foo { + cx: bool, +} + +impl Foo { + fn bar() { + f(cx); //~ ERROR E0425 + //~| HELP this is an associated function + } +} + +fn main() {} From 9bf603d3cde82690844f2b3ef67931499c99e4bf Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Sun, 22 May 2016 18:11:15 -0700 Subject: [PATCH 060/179] Fixed shortcut handling. Reverted to [Shift]+[+=] Realized browsers use [Ctrl]+[+=] for zoom, so using [Shift]+[+=] for collapse/expand was not necessarily a conflict. Also a bugfix. --- src/librustdoc/html/layout.rs | 2 +- src/librustdoc/html/static/main.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 0af64573926d..265ed6be1552 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -103,7 +103,7 @@ r##"
Move down in search results
Go to active search result
-
T
+
+
Collapse/expand all sections
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index e8f23c4709d4..14661dbaec4c 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -124,8 +124,8 @@ focusSearchBar(); break; - case "t": - case "T": + case "+": + ev.preventDefault(); toggleAllDocs(); break; From 3ff47f8d0bc950e7314bcae4cf59a797f57b69ba Mon Sep 17 00:00:00 2001 From: Brian Campbell Date: Sat, 6 Feb 2016 17:16:56 -0500 Subject: [PATCH 061/179] Use libc::abort, not intrinsics::abort, in rtabort! intrinsics::abort compiles down to an illegal instruction, which on Unix-like platforms causes the process to be killed with SIGILL. A more appropriate way to kill the process would be SIGABRT; this indicates better that the runtime has explicitly aborted, rather than some kind of compiler bug or architecture mismatch that SIGILL might indicate. For rtassert!, replace this with libc::abort. libc::abort raises SIGABRT, but is defined to do so in such a way that it will terminate the process even if SIGABRT is currently masked or caught by a signal handler that returns. On non-Unix platforms, retain the existing behavior. On Windows we prefer to avoid depending on the C runtime, and we need a fallback for any other platforms that may be defined. An alternative on Windows would be to call TerminateProcess, but this seems less essential than switching to using SIGABRT on Unix-like platforms, where it is common for the process-killing signal to be printed out or logged. This is a [breaking-change] for any code that depends on the exact signal raised to abort a process via rtabort! cc #31273 cc #31333 --- src/libstd/sys/common/util.rs | 26 ++++++++++++++++++++++++-- src/test/run-pass/out-of-stack.rs | 3 +-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/common/util.rs b/src/libstd/sys/common/util.rs index b7a6b7650d54..1df511a8818c 100644 --- a/src/libstd/sys/common/util.rs +++ b/src/libstd/sys/common/util.rs @@ -10,7 +10,6 @@ use env; use fmt; -use intrinsics; use io::prelude::*; use sync::atomic::{self, Ordering}; use sys::stdio::Stderr; @@ -34,9 +33,32 @@ pub fn dumb_print(args: fmt::Arguments) { let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); } +// On Unix-like platforms, libc::abort will unregister signal handlers +// including the SIGABRT handler, preventing the abort from being blocked, and +// fclose streams, with the side effect of flushing them so libc bufferred +// output will be printed. Additionally the shell will generally print a more +// understandable error message like "Abort trap" rather than "Illegal +// instruction" that intrinsics::abort would cause, as intrinsics::abort is +// implemented as an illegal instruction. +#[cfg(unix)] +unsafe fn abort_internal() -> ! { + use libc; + libc::abort() +} + +// On Windows, we want to avoid using libc, and there isn't a direct +// equivalent of libc::abort. The __failfast intrinsic may be a reasonable +// substitute, but desireability of using it over the abort instrinsic is +// debateable; see https://github.com/rust-lang/rust/pull/31519 for details. +#[cfg(not(unix))] +unsafe fn abort_internal() -> ! { + use intrinsics; + intrinsics::abort() +} + pub fn abort(args: fmt::Arguments) -> ! { dumb_print(format_args!("fatal runtime error: {}\n", args)); - unsafe { intrinsics::abort(); } + unsafe { abort_internal(); } } #[allow(dead_code)] // stack overflow detection not enabled on all platforms diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index 5ac037831850..a7748b6d6a2a 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -47,8 +47,7 @@ fn check_status(status: std::process::ExitStatus) use std::os::unix::process::ExitStatusExt; assert!(!status.success()); - assert!(status.signal() != Some(libc::SIGSEGV) - && status.signal() != Some(libc::SIGBUS)); + assert_eq!(status.signal(), Some(libc::SIGABRT)); } #[cfg(not(unix))] From 16a86a2b932d88a18af606fa63b2c6cf3efc7981 Mon Sep 17 00:00:00 2001 From: Masood Malekghassemi Date: Thu, 12 May 2016 18:01:23 -0700 Subject: [PATCH 062/179] Propagate obligations through projection --- src/librustc/traits/project.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 5c7095beb79c..44ec42de8cbd 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -207,7 +207,7 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( debug!("project_and_unify_type(obligation={:?})", obligation); - let Normalized { value: normalized_ty, obligations } = + let Normalized { value: normalized_ty, mut obligations } = match opt_normalize_projection_type(selcx, obligation.predicate.projection_ty.clone(), obligation.cause.clone(), @@ -224,8 +224,9 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); match infcx.eq_types(true, origin, normalized_ty, obligation.predicate.ty) { Ok(InferOk { obligations: inferred_obligations, .. }) => { - // FIXME(#32730) propagate obligations + // FIXME(#32730) once obligations are generated in inference, drop this assertion assert!(inferred_obligations.is_empty()); + obligations.extend(inferred_obligations); Ok(Some(obligations)) }, Err(err) => Err(MismatchedProjectionTypes { err: err }), @@ -710,7 +711,8 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( origin, data_poly_trait_ref, obligation_poly_trait_ref) - // FIXME(#32730) propagate obligations + // FIXME(#32730) once obligations are propagated from unification in + // inference, drop this assertion .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) .is_ok() }); @@ -1047,8 +1049,8 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>) -> (Ty<'tcx>, Vec>) { - // FIXME(#32730) propagate obligations (fn pointer vtable nested obligations ONLY come from - // unification in inference) + // FIXME(#32730) drop this assertion once obligations are propagated from inference (fn pointer + // vtable nested obligations ONLY come from unification in inference) assert!(fn_pointer_vtable.nested.is_empty()); let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); let sig = fn_type.fn_sig(); @@ -1130,13 +1132,14 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.item_name); let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - match infcx.eq_trait_refs(false, - origin, - obligation.predicate.trait_ref.clone(), - projection.projection_ty.trait_ref.clone()) { + let obligations = match infcx.eq_trait_refs(false, + origin, + obligation.predicate.trait_ref.clone(), + projection.projection_ty.trait_ref.clone()) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations + // FIXME(#32730) once obligations are generated in inference, remove this assertion assert!(obligations.is_empty()); + obligations } Err(e) => { span_bug!( @@ -1146,9 +1149,9 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( projection, e); } - } + }; - (projection.ty, vec!()) + (projection.ty, obligations) } fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( From b1a64c5059dbd6a61fe0a44f288335770ea7642d Mon Sep 17 00:00:00 2001 From: Tamir Bahar Date: Mon, 23 May 2016 14:42:47 +0300 Subject: [PATCH 063/179] Fixed link in Rust Book (no-stdlib) Fix a broken link in the rust book. --- src/doc/book/no-stdlib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/no-stdlib.md b/src/doc/book/no-stdlib.md index 43bd0507ebbb..9823a0b6d635 100644 --- a/src/doc/book/no-stdlib.md +++ b/src/doc/book/no-stdlib.md @@ -84,4 +84,4 @@ which do not trigger a panic can be assured that this function is never called. The second function, `panic_fmt`, is also used by the failure mechanisms of the compiler. -[unwind]: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/common/unwind/gcc.rs +[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs From 7ffebadf49704c63ea54f8b30960dd493390171b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 23 May 2016 14:31:52 +0200 Subject: [PATCH 064/179] add `indexed_set` mod for typed wrappers around bitarrays representing sets. It provides an `Idx` trait for usize wrappers used to represent the elements of such sets. --- src/librustc_borrowck/indexed_set.rs | 87 ++++++++++++++++++++++++++++ src/librustc_borrowck/lib.rs | 1 + 2 files changed, 88 insertions(+) create mode 100644 src/librustc_borrowck/indexed_set.rs diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs new file mode 100644 index 000000000000..c743e58aa996 --- /dev/null +++ b/src/librustc_borrowck/indexed_set.rs @@ -0,0 +1,87 @@ +// Copyright 2012-2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use bitslice::{BitSlice, Word}; + +pub trait Indexed { + type Idx: Idx; +} + +pub trait Idx { + fn idx(&self) -> usize; +} + +pub struct OwnIdxSet { + _pd: PhantomData &T>, + bits: Vec, +} + +// pnkfelix wants to have this be `IdxSet([Word]) and then pass +// around `&mut IdxSet` or `&IdxSet`. +// +// Mmapping a `&OwnIdxSet` to `&IdxSet` (at least today) +// requires a transmute relying on representation guarantees that may +// not hold in the future. + +pub struct IdxSet { + _pd: PhantomData &T>, + bits: [Word], +} + +impl fmt::Debug for OwnIdxSet { + fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) } +} + +impl fmt::Debug for IdxSet { + fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) } +} + +impl OwnIdxSet { + fn new(init: Word, universe_size: usize) -> Self { + let bits_per_word = mem::size_of::(); + let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word; + OwnIdxSet { + _pd: Default::default(), + bits: vec![init; num_words], + } + } + + /// Creates set holding every element whose index falls in range 0..universe_size. + pub fn new_filled(universe_size: usize) -> Self { + Self::new(!0, universe_size) + } + + /// Creates set holding no elements. + pub fn new_empty(universe_size: usize) -> Self { + Self::new(0, universe_size) + } + + /// Removes `elem` from the set `self`; returns true iff this changed `self`. + pub fn clear(&mut self, elem: &T) -> bool { + self.bits.clear_bit(elem.idx()) + } + + /// Adds `elem` to the set `self`; returns true iff this changed `self`. + pub fn add(&mut self, elem: &T) -> bool { + self.bits.set_bit(elem.idx()) + } + + /// Returns true iff set `self` contains `elem`. + pub fn contains(&self, elem: &T) -> bool { + self.bits.get_bit(elem.idx()) + } + + pub fn bits(&self) -> &[Word] { + &self.bits[..] + } +} diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index e38677de6625..9d7e05ed9fa8 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -47,6 +47,7 @@ pub mod diagnostics; mod borrowck; mod bitslice; +mod indexed_set; pub mod graphviz; From c35e4fa3ab791009cefa6d50e64fec64ed8d3a34 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 20 May 2016 15:50:34 -0400 Subject: [PATCH 065/179] Add explanations about what derived trait implementations do --- src/libcore/clone.rs | 3 ++- src/libcore/cmp.rs | 9 +++++++-- src/libcore/fmt/mod.rs | 6 +++++- src/libcore/hash/mod.rs | 4 +++- src/libcore/marker.rs | 3 ++- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index e8ea993c6940..cfb29cf479d8 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -48,7 +48,8 @@ use marker::Sized; /// A common trait for cloning an object. /// -/// This trait can be used with `#[derive]`. +/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d +/// implementation of `clone()` calls `clone()` on each field. /// /// Types that are `Copy` should have a trivial implementation of `Clone`. More formally: /// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`. diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index d3481ba3f052..cd0bbcd33569 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -58,7 +58,10 @@ use option::Option::{self, Some}; /// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and /// only if `a != b`. /// -/// This trait can be used with `#[derive]`. +/// This trait can be used with `#[derive]`. When `derive`d on structs, two +/// instances are equal if all fields are equal, and non equal if any fields +/// are not equal. When `derive`d on enums, each variant is equal to itself +/// and not equal to the other variants. /// /// # Examples /// @@ -96,7 +99,9 @@ pub trait PartialEq { /// This property cannot be checked by the compiler, and therefore `Eq` implies /// `PartialEq`, and has no extra methods. /// -/// This trait can be used with `#[derive]`. +/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has +/// no extra methods, it is only informing the compiler that this is an +/// equivalence relation rather than a partial equivalence relation. #[stable(feature = "rust1", since = "1.0.0")] pub trait Eq: PartialEq { // FIXME #13101: this method is used solely by #[deriving] to diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index dde4d03dad8a..6579e5dab543 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -318,7 +318,11 @@ impl<'a> Display for Arguments<'a> { /// /// [module]: ../../std/fmt/index.html /// -/// This trait can be used with `#[derive]`. +/// This trait can be used with `#[derive]` if all fields implement `Debug`. When +/// `derive`d for structs, it will use the name of the `struct`, then `{`, then a +/// comma-separated list of each field's name and `Debug` value, then `}`. For +/// `enum`s, it will use the name of the variant and, if applicable, `(`, then the +/// `Debug` values of the fields, then `)`. /// /// # Examples /// diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 4d0fed983343..7f0d7517a57c 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -97,7 +97,9 @@ mod sip; /// In other words, if two keys are equal, their hashes should also be equal. /// `HashMap` and `HashSet` both rely on this behavior. /// -/// This trait can be used with `#[derive]`. +/// This trait can be used with `#[derive]` if all fields implement `Hash`. +/// When `derive`d, the resulting hash will be the combination of the values +/// from calling `.hash()` on each field. #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { /// Feeds this value into the state given, updating the hasher as necessary. diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 1ed2a219fac3..e519071a56ee 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -173,7 +173,8 @@ pub trait Unsize { /// /// # Derivable /// -/// This trait can be used with `#[derive]`. +/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type +/// implements `Clone`. The implementation will copy the bytes of each field using `memcpy`. #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { From 51d2fd75a53ca3488c277cd6c75b82add3da3503 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 21 May 2016 10:39:31 -0400 Subject: [PATCH 066/179] `derive` explanation for PartialOrd should match that for Ord I think these just got out of sync, but both use a lexicographic ordering. Relevant commits in the history of these explanations: * 8b81f76 on 2015-06-30 * e22770b on 2016-02-09 --- src/libcore/cmp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index cd0bbcd33569..75cd56b79f48 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -254,8 +254,8 @@ impl PartialOrd for Ordering { /// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == /// false` (cf. IEEE 754-2008 section 5.11). /// -/// This trait can be used with `#[derive]`. When `derive`d, it will produce an ordering -/// based on the top-to-bottom declaration order of the struct's members. +/// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic +/// ordering based on the top-to-bottom declaration order of the struct's members. /// /// # Examples /// From ed59f6bde90861cd185e0a78b667a7db7055cd8d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 21 May 2016 12:01:01 -0400 Subject: [PATCH 067/179] Make `Derivable` header be an h2 instead of an h1 This matches the other subsections. --- src/libcore/marker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index e519071a56ee..150a091c4bd3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -171,7 +171,7 @@ pub trait Unsize { /// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking /// change: that second example would fail to compile if we made `Foo` non-`Copy`. /// -/// # Derivable +/// ## Derivable /// /// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type /// implements `Clone`. The implementation will copy the bytes of each field using `memcpy`. From 5f81879b9fd2e7592a8a717c44c59ba7bb28c568 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 21 May 2016 11:54:29 -0400 Subject: [PATCH 068/179] Reorder `Copy` doc sections The new order puts all the "when" questions together and puts the "how" question with the "derivable" section. So you have to scroll past (and hopefully read) the can/cannot/should caveats and guidelines to get to the information about how to actually go about doing it once you've determined that you can and should, with derivable information first so that you can just use the derived implementation if that applies. Previous order: * General explanation * When can my type be `Copy`? * How can I implement `Copy`? * When can my type _not_ be `Copy`? * When should my type be `Copy`? * Derivable New order: * General explanation * When can my type be `Copy`? * When can my type _not_ be `Copy`? * When should my type be `Copy`? * Derivable * How can I implement `Copy`? --- src/libcore/marker.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 150a091c4bd3..c18d230be31a 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -136,26 +136,6 @@ pub trait Unsize { /// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy` /// ``` /// -/// ## How can I implement `Copy`? -/// -/// There are two ways to implement `Copy` on your type: -/// -/// ``` -/// #[derive(Copy, Clone)] -/// struct MyStruct; -/// ``` -/// -/// and -/// -/// ``` -/// struct MyStruct; -/// impl Copy for MyStruct {} -/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } } -/// ``` -/// -/// There is a small difference between the two: the `derive` strategy will also place a `Copy` -/// bound on type parameters, which isn't always desired. -/// /// ## When can my type _not_ be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased @@ -175,6 +155,26 @@ pub trait Unsize { /// /// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type /// implements `Clone`. The implementation will copy the bytes of each field using `memcpy`. +/// +/// ## How can I implement `Copy`? +/// +/// There are two ways to implement `Copy` on your type: +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct MyStruct; +/// ``` +/// +/// and +/// +/// ``` +/// struct MyStruct; +/// impl Copy for MyStruct {} +/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } } +/// ``` +/// +/// There is a small difference between the two: the `derive` strategy will also place a `Copy` +/// bound on type parameters, which isn't always desired. #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { From 7529f15d21c182bdcef9f1107c98ac5d506dd5ca Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 21 May 2016 12:55:13 -0400 Subject: [PATCH 069/179] Add an explicit "How can I implement `PartialEq`"? doc section Including an example of a custom implementation. I put this expanded section after the `Derivable` section to encourage use of that first. --- src/libcore/cmp.rs | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 75cd56b79f48..f99358b09f4c 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -53,16 +53,43 @@ use option::Option::{self, Some}; /// symmetrically and transitively: if `T: PartialEq` and `U: PartialEq` /// then `U: PartialEq` and `T: PartialEq`. /// -/// PartialEq only requires the `eq` method to be implemented; `ne` is defined -/// in terms of it by default. Any manual implementation of `ne` *must* respect -/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and -/// only if `a != b`. +/// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d on structs, two /// instances are equal if all fields are equal, and non equal if any fields /// are not equal. When `derive`d on enums, each variant is equal to itself /// and not equal to the other variants. /// +/// ## How can I implement `PartialEq`? +/// +/// PartialEq only requires the `eq` method to be implemented; `ne` is defined +/// in terms of it by default. Any manual implementation of `ne` *must* respect +/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and +/// only if `a != b`. +/// +/// An example implementation for a domain in which two books are considered +/// the same book if their ISBN matches, even if the formats differ: +/// +/// ``` +/// enum BookFormat { Paperback, Hardback, Ebook } +/// struct Book { +/// isbn: i32, +/// format: BookFormat, +/// } +/// impl PartialEq for Book { +/// fn eq(&self, other: &Self) -> bool { +/// self.isbn == other.isbn +/// } +/// } +/// +/// let b1 = Book { isbn: 3, format: BookFormat::Paperback }; +/// let b2 = Book { isbn: 3, format: BookFormat::Ebook }; +/// let b3 = Book { isbn: 10, format: BookFormat::Paperback }; +/// +/// assert!(b1 == b2); +/// assert!(b1 != b3); +/// ``` +/// /// # Examples /// /// ``` From 2db5288a61843cda6b686e2171f60dbc540a4340 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 21 May 2016 13:05:15 -0400 Subject: [PATCH 070/179] Add an explicit "How can I implement `Eq`" doc section Building on the example in PartialEq. --- src/libcore/cmp.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index f99358b09f4c..d536d3ada3ff 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -126,9 +126,32 @@ pub trait PartialEq { /// This property cannot be checked by the compiler, and therefore `Eq` implies /// `PartialEq`, and has no extra methods. /// +/// ## Derivable +/// /// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has /// no extra methods, it is only informing the compiler that this is an -/// equivalence relation rather than a partial equivalence relation. +/// equivalence relation rather than a partial equivalence relation. Note that +/// the `derive` strategy requires all fields are `PartialEq`, which isn't +/// always desired. +/// +/// ## How can I implement `Eq`? +/// +/// If you cannot use the `derive` strategy, specify that your type implements +/// `Eq`, which has no methods: +/// +/// ``` +/// enum BookFormat { Paperback, Hardback, Ebook } +/// struct Book { +/// isbn: i32, +/// format: BookFormat, +/// } +/// impl PartialEq for Book { +/// fn eq(&self, other: &Self) -> bool { +/// self.isbn == other.isbn +/// } +/// } +/// impl Eq for Book {} +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Eq: PartialEq { // FIXME #13101: this method is used solely by #[deriving] to From 9eebf37c4627e254cc944ccd526391dafc185648 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 22 May 2016 18:06:13 -0400 Subject: [PATCH 071/179] Add more detail to `Clone`'s documentation Used as resources: - https://users.rust-lang.org/t/whats-the-difference-between-trait-copy-and-clone/2609/2?u=carols10cents --- src/libcore/clone.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index cfb29cf479d8..629808cb1243 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -46,15 +46,39 @@ use marker::Sized; -/// A common trait for cloning an object. +/// A common trait for cloning an object. Differs from `Copy` in that you can +/// define `Clone` to run arbitrary code, while you are not allowed to override +/// the implementation of `Copy` that only does a `memcpy`. +/// +/// Since `Clone` is more general than `Copy`, you can automatically make anything +/// `Copy` be `Clone` as well. +/// +/// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d /// implementation of `clone()` calls `clone()` on each field. /// +/// ## How can I implement `Clone`? +/// /// Types that are `Copy` should have a trivial implementation of `Clone`. More formally: /// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`. /// Manual implementations should be careful to uphold this invariant; however, unsafe code /// must not rely on it to ensure memory safety. +/// +/// An example is an array holding more than 32 of a type that is `Clone`; the standard library +/// only implements `Clone` up until arrays of size 32. In this case, the implementation of +/// `Clone` cannot be `derive`d, but can be implemented as: +/// +/// ``` +/// #[derive(Copy)] +/// struct Stats { +/// frequencies: [i32; 100], +/// } +/// +/// impl Clone for Stats { +/// fn clone(&self) -> Self { *self } +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Clone : Sized { /// Returns a copy of the value. From 8c8aba4491cafa6ca8e4c3445130a4b10de711b2 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 22 May 2016 18:29:13 -0400 Subject: [PATCH 072/179] Add more information about implementing `Hash` A bit of duplication from the module documentation, but simplified to be closer to being trivially copy-paste-able. --- src/libcore/hash/mod.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 7f0d7517a57c..844a24e80d1a 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -97,9 +97,33 @@ mod sip; /// In other words, if two keys are equal, their hashes should also be equal. /// `HashMap` and `HashSet` both rely on this behavior. /// +/// ## Derivable +/// /// This trait can be used with `#[derive]` if all fields implement `Hash`. /// When `derive`d, the resulting hash will be the combination of the values /// from calling `.hash()` on each field. +/// +/// ## How can I implement `Hash`? +/// +/// If you need more control over how a value is hashed, you need to implement +/// the trait `Hash`: +/// +/// ``` +/// use std::hash::{Hash, Hasher}; +/// +/// struct Person { +/// id: u32, +/// name: String, +/// phone: u64, +/// } +/// +/// impl Hash for Person { +/// fn hash(&self, state: &mut H) { +/// self.id.hash(state); +/// self.phone.hash(state); +/// } +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { /// Feeds this value into the state given, updating the hasher as necessary. From 7be67107d5aae6e8ebd5a63f4a131c6e0bbfc6fa Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 22 May 2016 19:02:38 -0400 Subject: [PATCH 073/179] Add an explicit "How can I implement `Ord`" doc section References: - http://stackoverflow.com/q/29884402/51683 - http://stackoverflow.com/q/28387711/51683 --- src/libcore/cmp.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index d536d3ada3ff..15e128c57da7 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -245,8 +245,48 @@ impl Ordering { /// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and /// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. /// +/// ## Derivable +/// /// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic /// ordering based on the top-to-bottom declaration order of the struct's members. +/// +/// ## How can I implement `Ord`? +/// +/// `Ord` requires that the type also be `PartialOrd` and `Eq` (which requires `PartialEq`). +/// +/// Then you must define an implementation for `cmp`. You may find it useful to use +/// `cmp` on your type's fields. +/// +/// Here's an example where you want to sort people by height only, disregarding `id` +/// and `name`: +/// +/// ``` +/// use std::cmp::Ordering; +/// #[derive(Eq)] +/// struct Person { +/// id: u32, +/// name: String, +/// height: u32, +/// } +/// +/// impl Ord for Person { +/// fn cmp(&self, other: &Self) -> Ordering { +/// self.height.cmp(&other.height) +/// } +/// } +/// +/// impl PartialOrd for Person { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.cmp(other)) +/// } +/// } +/// +/// impl PartialEq for Person { +/// fn eq(&self, other: &Self) -> bool { +/// self.height == other.height +/// } +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. From c01cc02bf09efd6f687391271260580ce0ba0445 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 22 May 2016 19:14:38 -0400 Subject: [PATCH 074/179] Add an explicit "How can I implement `PartialOrd`" doc section Similar to the `Ord` examples but calling out that it can be defined using `cmp` from `Ord` or using `partial_cmp` in a situation that demands that. --- src/libcore/cmp.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 15e128c57da7..5b8620f4b8eb 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -337,6 +337,13 @@ impl PartialOrd for Ordering { /// transitively: if `T: PartialOrd` and `U: PartialOrd` then `U: PartialOrd` and `T: /// PartialOrd`. /// +/// ## Derivable +/// +/// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic +/// ordering based on the top-to-bottom declaration order of the struct's members. +/// +/// ## How can I implement `Ord`? +/// /// PartialOrd only requires implementation of the `partial_cmp` method, with the others generated /// from default implementations. /// @@ -344,8 +351,43 @@ impl PartialOrd for Ordering { /// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == /// false` (cf. IEEE 754-2008 section 5.11). /// -/// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic -/// ordering based on the top-to-bottom declaration order of the struct's members. +/// `PartialOrd` requires your type to be `PartialEq`. +/// +/// If your type is `Ord`, you can implement `partial_cmp` by using `cmp`: +/// +/// ``` +/// impl PartialOrd for Person { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.cmp(other)) +/// } +/// } +/// ``` +/// +/// You may also find it useful to use `partial_cmp` on your type`s fields. Here +/// is an example of `Person` types who have a floating-point `height` field that +/// is the only field to be used for sorting: +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// struct Person { +/// id: u32, +/// name: String, +/// height: f64, +/// } +/// +/// impl PartialOrd for Person { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// self.height.partial_cmp(&other.height) +/// } +/// } +/// +/// impl PartialEq for Person { +/// fn eq(&self, other: &Self) -> bool { +/// self.height == other.height +/// } +/// } +/// ``` /// /// # Examples /// From 6b00de7e2d315de2e48c0e322cd4c02257726720 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 22 May 2016 19:24:58 -0400 Subject: [PATCH 075/179] Make the Default docs more like the other traits Add explicit "Derivable" and "How can I implement `Default`" sections. Copied relevant sections from the module-level documentation, but also linked to there-- it has a more comprehensive narrative with examples that show implementation AND use. Decided to just put implementation example in the trait documentation. --- src/libcore/default.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 12c4a5ca200a..74101c66c97a 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -84,10 +84,33 @@ use marker::Sized; -/// A trait for giving a type a useful default value. +/// A trait for giving a type a useful default value. For more information, see +/// [the module-level documentation][module]. /// -/// A struct can derive default implementations of `Default` for basic types using -/// `#[derive(Default)]`. +/// [module]: ../../std/default/index.html +/// +/// ## Derivable +/// +/// This trait can be used with `#[derive]` if all of the type's fields implement +/// `Default`. When `derive`d, it will use the default value for each field's type. +/// +/// ## How can I implement `Default`? +/// +/// Provide an implementation for the `default()` method that returns the value of +/// your type that should be the default: +/// +/// ``` +/// # #![allow(dead_code)] +/// enum Kind { +/// A, +/// B, +/// C, +/// } +/// +/// impl Default for Kind { +/// fn default() -> Kind { Kind::A } +/// } +/// ``` /// /// # Examples /// From 2ca56974523a7d4a7c9e0959b7addb21117395aa Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 22 May 2016 00:47:21 -0400 Subject: [PATCH 076/179] trans::collector: Remove some redundant calls to erase_regions(). --- src/librustc/ty/fold.rs | 10 +++++++++ src/librustc_trans/collector.rs | 22 ++++++++++--------- src/librustc_trans/glue.rs | 10 +++++---- .../instantiation-through-vtable.rs | 2 ++ .../codegen-units/item-collection/unsizing.rs | 2 ++ 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 4a14185b6e3a..f76f4c01df34 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -99,6 +99,16 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { TypeFlags::HAS_RE_INFER | TypeFlags::HAS_FREE_REGIONS) } + fn is_normalized_for_trans(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND | + TypeFlags::HAS_RE_INFER | + TypeFlags::HAS_FREE_REGIONS | + TypeFlags::HAS_TY_INFER | + TypeFlags::HAS_PARAMS | + TypeFlags::HAS_PROJECTION | + TypeFlags::HAS_TY_ERR | + TypeFlags::HAS_SELF) + } /// Indicates whether this value references only 'global' /// types/lifetimes that are the same regardless of what fn we are /// in. This is used for caching. Errs on the side of returning diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index d278c3c8320f..bbc01f0935f2 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let ty = monomorphize::apply_param_substs(self.scx.tcx(), self.param_substs, &ty); - let ty = self.scx.tcx().erase_regions(&ty); + assert!(ty.is_normalized_for_trans()); let ty = glue::get_drop_glue_type(self.scx.tcx(), ty); self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); } @@ -859,6 +859,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, &callee_substs); let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id)); + let trait_ref = tcx.normalize_associated_type(&trait_ref); let vtbl = fulfill_obligation(scx, DUMMY_SP, trait_ref); // Now that we know which impl is being used, we can dispatch to @@ -992,11 +993,8 @@ fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let concrete_substs = monomorphize::apply_param_substs(tcx, param_substs, &fn_substs); - let concrete_substs = tcx.erase_regions(&concrete_substs); - - let trans_item = - TransItem::Fn(Instance::new(def_id, concrete_substs)); - return trans_item; + assert!(concrete_substs.is_normalized_for_trans()); + TransItem::Fn(Instance::new(def_id, concrete_substs)) } /// Creates a `TransItem` for each method that is referenced by the vtable for @@ -1034,10 +1032,14 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, } else { None } - }) - .collect::>(); + }); + + output.extend(items); - output.extend(items.into_iter()); + // Also add the destructor + let dg_type = glue::get_drop_glue_type(scx.tcx(), + trait_ref.self_ty()); + output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); } _ => { /* */ } } @@ -1234,7 +1236,7 @@ pub enum TransItemState { } pub fn collecting_debug_information(scx: &SharedCrateContext) -> bool { - return scx.sess().opts.cg.debug_assertions == Some(true) && + return cfg!(debug_assertions) && scx.sess().opts.debugging_opts.print_trans_items.is_some(); } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 10e33195305f..64e178bf9196 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -20,7 +20,7 @@ use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; use rustc::ty::subst::{Substs}; use rustc::traits; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use abi::{Abi, FnType}; use adt; use adt::GetDtorType; // for tcx.dtor_type() @@ -96,10 +96,12 @@ pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { + assert!(t.is_normalized_for_trans()); + // Even if there is no dtor for t, there might be one deeper down and we // might need to pass in the vtable ptr. if !type_is_sized(tcx, t) { - return tcx.erase_regions(&t); + return t; } // FIXME (#22815): note that type_needs_drop conservatively @@ -123,11 +125,11 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `Box` does not allocate. tcx.types.i8 } else { - tcx.erase_regions(&t) + t } }) } - _ => tcx.erase_regions(&t) + _ => t } } diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index b77252512200..06e547f0dd03 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -40,3 +40,5 @@ fn main() { //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; } + +//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 45ba441bc8ba..5c67ab7a8264 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -78,3 +78,5 @@ fn main() //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; } + +//~ TRANS_ITEM drop-glue i8 From 05088e7f3094d92494f510d03fed02f2dc9e76ae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 23 May 2016 07:56:43 -0700 Subject: [PATCH 077/179] mk: Bump version number The 1.10 betas are now under way so we're now working on the 1.11 release. --- mk/main.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index 6feb53ec7b17..14504d5cf5c8 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -13,7 +13,7 @@ ###################################################################### # The version number -CFG_RELEASE_NUM=1.10.0 +CFG_RELEASE_NUM=1.11.0 # An optional number to put after the label, e.g. '.2' -> '-beta.2' # NB Make sure it starts with a dot to conform to semver pre-release From 0ed92d6f0fd124ab9ae50f5c1a0d103e4bcb551c Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 24 May 2016 00:44:44 +0900 Subject: [PATCH 078/179] Do not inject test harness for --cfg test --- src/librustc_driver/driver.rs | 6 +++++- src/libsyntax/test.rs | 6 +----- src/test/run-pass/test-vs-cfg-test.rs | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/test-vs-cfg-test.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1f3df1ff6f2d..2965c763ccc4 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -743,7 +743,11 @@ pub fn phase_2_configure_and_expand(sess: &Session, })?; krate = time(time_passes, "maybe building test harness", || { - syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic()) + syntax::test::modify_for_testing(&sess.parse_sess, + sess.opts.test, + &sess.opts.cfg, + krate, + sess.diagnostic()) }); krate = time(time_passes, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 8eeb61e0de46..56485433101f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -68,14 +68,10 @@ struct TestCtxt<'a> { // Traverse the crate, collecting all the test functions, eliding any // existing main functions, and synthesizing a main test harness pub fn modify_for_testing(sess: &ParseSess, + should_test: bool, cfg: &ast::CrateConfig, krate: ast::Crate, span_diagnostic: &errors::Handler) -> ast::Crate { - // We generate the test harness when building in the 'test' - // configuration, either with the '--test' or '--cfg test' - // command line options. - let should_test = attr::contains_name(&krate.config, "test"); - // Check for #[reexport_test_harness_main = "some_name"] which // creates a `use some_name = __test::main;`. This needs to be // unconditional, so that the attribute is still marked as used in diff --git a/src/test/run-pass/test-vs-cfg-test.rs b/src/test/run-pass/test-vs-cfg-test.rs new file mode 100644 index 000000000000..708fde598886 --- /dev/null +++ b/src/test/run-pass/test-vs-cfg-test.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --cfg test + +// Make sure `--cfg test` does not inject test harness + +#[test] +fn test() { panic!(); } + +fn main() {} From ab86cc45dcda13bf41b1a9b9bc17cb440cd68e84 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 23 May 2016 18:26:52 +0200 Subject: [PATCH 079/179] revised mir-dataflow so bitvectors carry a phantom type for their index domain. As some drive-by's: * moved bitwise operators into `mod bitslice` * factored out `fn gen` and `fn kill` methods on `BlockSets` type * removed outdated comment about `fn propagate_call_return` --- src/librustc_borrowck/bitslice.rs | 29 ++ .../borrowck/mir/dataflow/graphviz.rs | 11 +- .../borrowck/mir/dataflow/mod.rs | 297 +++++++++--------- .../borrowck/mir/dataflow/sanity_check.rs | 23 +- .../borrowck/mir/gather_moves.rs | 17 +- src/librustc_borrowck/indexed_set.rs | 75 ++++- 6 files changed, 272 insertions(+), 180 deletions(-) diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_borrowck/bitslice.rs index 1c01e98cf859..7a203b7f0b71 100644 --- a/src/librustc_borrowck/bitslice.rs +++ b/src/librustc_borrowck/bitslice.rs @@ -109,3 +109,32 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { result.push(']'); return result } + +#[inline] +pub fn bitwise(out_vec: &mut [usize], + in_vec: &[usize], + op: &Op) -> bool { + assert_eq!(out_vec.len(), in_vec.len()); + let mut changed = false; + for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) { + let old_val = *out_elt; + let new_val = op.join(old_val, *in_elt); + *out_elt = new_val; + changed |= old_val != new_val; + } + changed +} + +pub trait BitwiseOperator { + /// Applies some bit-operation pointwise to each of the bits in the two inputs. + fn join(&self, pred1: usize, pred2: usize) -> usize; +} + +pub struct Union; +impl BitwiseOperator for Union { + fn join(&self, a: usize, b: usize) -> usize { a | b } +} +pub struct Subtract; +impl BitwiseOperator for Subtract { + fn join(&self, a: usize, b: usize) -> usize { a & !b } +} diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index bc6ee89fa257..5a8b3ec32062 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -54,8 +54,9 @@ struct Graph<'a, 'tcx, MWF:'a> where MWF: MirWithFlowState<'tcx>, pub fn print_borrowck_graph_to<'a, 'tcx, BD>( mbcx: &MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>, - path: &Path) -> io::Result<()> where BD: BitDenotation, - BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> + path: &Path) + -> io::Result<()> + where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx>, { let g = Graph { mbcx: mbcx, phantom: PhantomData }; let mut v = Vec::new(); @@ -180,7 +181,7 @@ impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> ", bg = BG_FLOWCONTENT, face = FACE_MONOSPACE, - entrybits=bits_to_string(entry, bits_per_block)) + entrybits=bits_to_string(entry.words(), bits_per_block)) }, |w| { let ctxt = self.mbcx.analysis_ctxt(); @@ -197,7 +198,7 @@ impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> ", bg = BG_FLOWCONTENT, face = FACE_MONOSPACE, - genbits=bits_to_string(gen, bits_per_block))?; + genbits=bits_to_string(gen.words(), bits_per_block))?; } { @@ -209,7 +210,7 @@ impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> bg = BG_FLOWCONTENT, align = ALIGN_RIGHT, face = FACE_MONOSPACE, - killbits=bits_to_string(kill, bits_per_block))?; + killbits=bits_to_string(kill.words(), bits_per_block))?; } // (chunked_present_right) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 09abbb6af681..e1459ad2abea 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -24,6 +24,8 @@ use super::gather_moves::{MoveOut, MovePath}; use super::DropFlagState; use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. +use bitslice::{bitwise, BitwiseOperator}; +use indexed_set::{Idx, IdxSet, OwnIdxSet}; pub use self::sanity_check::sanity_check_via_rustc_peek; @@ -35,7 +37,9 @@ pub trait Dataflow { } impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation + DataflowOperator, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation + DataflowOperator, + BD::Bit: Debug, + BD::Ctxt: HasMoveData<'tcx> { fn dataflow(&mut self) { self.flow_state.build_sets(); @@ -46,7 +50,7 @@ impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> } struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> - where O: 'b + BitDenotation, O::Ctxt: HasMoveData<'tcx>, + where O: 'b + BitDenotation, O::Ctxt: HasMoveData<'tcx> { builder: &'b mut DataflowAnalysis<'a, 'tcx, O>, changed: bool, @@ -56,7 +60,7 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx> { fn propagate(&mut self) { - let mut temp = vec![0; self.flow_state.sets.words_per_block]; + let mut temp = OwnIdxSet::new_empty(self.flow_state.sets.bits_per_block); let mut propcx = PropagationContext { builder: self, changed: true, @@ -102,23 +106,23 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx> { - fn reset(&mut self, bits: &mut [usize]) { - let e = if BD::bottom_value() {usize::MAX} else {0}; - for b in bits { + fn reset(&mut self, bits: &mut IdxSet) { + let e = if BD::bottom_value() {!0} else {0}; + for b in bits.words_mut() { *b = e; } } - fn walk_cfg(&mut self, in_out: &mut [usize]) { + fn walk_cfg(&mut self, in_out: &mut IdxSet) { let mir = self.builder.mir; for (bb_idx, bb_data) in mir.basic_blocks.iter().enumerate() { let builder = &mut self.builder; { let sets = builder.flow_state.sets.for_block(bb_idx); - debug_assert!(in_out.len() == sets.on_entry.len()); - in_out.clone_from_slice(sets.on_entry); - bitwise(in_out, sets.gen_set, &Union); - bitwise(in_out, sets.kill_set, &Subtract); + debug_assert!(in_out.words().len() == sets.on_entry.words().len()); + in_out.clone_from(sets.on_entry); + in_out.union(sets.gen_set); + in_out.subtract(sets.kill_set); } builder.propagate_bits_into_graph_successors_of(in_out, &mut self.changed, @@ -161,14 +165,18 @@ impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> } /// Maps each block to a set of bits -#[derive(Clone, Debug)] -struct Bits { - bits: Vec, +#[derive(Debug)] +struct Bits { + bits: OwnIdxSet, +} + +impl Clone for Bits { + fn clone(&self) -> Self { Bits { bits: self.bits.clone() } } } -impl Bits { - fn new(init_word: usize, num_words: usize) -> Self { - Bits { bits: vec![init_word; num_words] } +impl Bits { + fn new(bits: OwnIdxSet) -> Self { + Bits { bits: bits } } } @@ -201,25 +209,23 @@ impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> pub fn mir(&self) -> &'a Mir<'tcx> { self.mir } } -#[derive(Debug)] -pub struct DataflowResults(DataflowState); +pub struct DataflowResults(DataflowState) where O: BitDenotation; // FIXME: This type shouldn't be public, but the graphviz::MirWithFlowState trait // references it in a method signature. Look into using `pub(crate)` to address this. -#[derive(Debug)] pub struct DataflowState { /// All the sets for the analysis. (Factored into its /// own structure so that we can borrow it mutably /// on its own separate from other fields.) - pub sets: AllSets, + pub sets: AllSets, /// operator used to initialize, combine, and interpret bits. operator: O, } #[derive(Debug)] -pub struct AllSets { +pub struct AllSets { /// Analysis bitwidth for each block. bits_per_block: usize, @@ -230,59 +236,71 @@ pub struct AllSets { /// For each block, bits generated by executing the statements in /// the block. (For comparison, the Terminator for each block is /// handled in a flow-specific manner during propagation.) - gen_sets: Bits, + gen_sets: Bits, /// For each block, bits killed by executing the statements in the /// block. (For comparison, the Terminator for each block is /// handled in a flow-specific manner during propagation.) - kill_sets: Bits, + kill_sets: Bits, /// For each block, bits valid on entry to the block. - on_entry_sets: Bits, + on_entry_sets: Bits, } -pub struct BlockSets<'a> { - on_entry: &'a mut [usize], - gen_set: &'a mut [usize], - kill_set: &'a mut [usize], +pub struct BlockSets<'a, E: Idx> { + on_entry: &'a mut IdxSet, + gen_set: &'a mut IdxSet, + kill_set: &'a mut IdxSet, } -impl AllSets { +impl<'a, E:Idx> BlockSets<'a, E> { + fn gen(&mut self, e: &E) { + self.gen_set.add(e); + self.kill_set.remove(e); + } + fn kill(&mut self, e: &E) { + self.gen_set.remove(e); + self.kill_set.add(e); + } +} + +impl AllSets { pub fn bits_per_block(&self) -> usize { self.bits_per_block } - pub fn for_block(&mut self, block_idx: usize) -> BlockSets { + pub fn for_block(&mut self, block_idx: usize) -> BlockSets { let offset = self.words_per_block * block_idx; - let range = offset..(offset + self.words_per_block); + let range = E::new(offset)..E::new(offset + self.words_per_block); BlockSets { - on_entry: &mut self.on_entry_sets.bits[range.clone()], - gen_set: &mut self.gen_sets.bits[range.clone()], - kill_set: &mut self.kill_sets.bits[range], + on_entry: self.on_entry_sets.bits.range_mut(&range), + gen_set: self.gen_sets.bits.range_mut(&range), + kill_set: self.kill_sets.bits.range_mut(&range), } } - fn lookup_set_for<'a>(&self, sets: &'a Bits, block_idx: usize) -> &'a [usize] { + fn lookup_set_for<'a>(&self, sets: &'a Bits, block_idx: usize) -> &'a IdxSet { let offset = self.words_per_block * block_idx; - &sets.bits[offset..(offset + self.words_per_block)] + let range = E::new(offset)..E::new(offset + self.words_per_block); + sets.bits.range(&range) } - pub fn gen_set_for(&self, block_idx: usize) -> &[usize] { + pub fn gen_set_for(&self, block_idx: usize) -> &IdxSet { self.lookup_set_for(&self.gen_sets, block_idx) } - pub fn kill_set_for(&self, block_idx: usize) -> &[usize] { + pub fn kill_set_for(&self, block_idx: usize) -> &IdxSet { self.lookup_set_for(&self.kill_sets, block_idx) } - pub fn on_entry_set_for(&self, block_idx: usize) -> &[usize] { + pub fn on_entry_set_for(&self, block_idx: usize) -> &IdxSet { self.lookup_set_for(&self.on_entry_sets, block_idx) } } impl DataflowState { - fn each_bit(&self, ctxt: &O::Ctxt, words: &[usize], mut f: F) + fn each_bit(&self, ctxt: &O::Ctxt, words: &IdxSet, mut f: F) where F: FnMut(usize) { //! Helper for iterating over the bits in a bitvector. let bits_per_block = self.operator.bits_per_block(ctxt); let usize_bits: usize = mem::size_of::() * 8; - for (word_index, &word) in words.iter().enumerate() { + for (word_index, &word) in words.words().iter().enumerate() { if word != 0 { let base_index = word_index * usize_bits; for offset in 0..usize_bits { @@ -307,7 +325,7 @@ impl DataflowState { } } - pub fn interpret_set<'c>(&self, ctxt: &'c O::Ctxt, words: &[usize]) -> Vec<&'c O::Bit> { + pub fn interpret_set<'c>(&self, ctxt: &'c O::Ctxt, words: &IdxSet) -> Vec<&'c O::Bit> { let mut v = Vec::new(); self.each_bit(ctxt, words, |i| { v.push(self.operator.interpret(ctxt, i)); @@ -316,11 +334,6 @@ impl DataflowState { } } -pub trait BitwiseOperator { - /// Applies some bit-operation pointwise to each of the bits in the two inputs. - fn join(&self, pred1: usize, pred2: usize) -> usize; -} - /// Parameterization for the precise form of data flow that is used. pub trait DataflowOperator: BitwiseOperator { /// Specifies the initial value for each bit in the `on_entry` set @@ -331,6 +344,9 @@ pub trait BitDenotation { /// Specifies what is represented by each bit in the dataflow bitvector. type Bit; + /// Specifies what index type is used to access the bitvector. + type Idx: Idx; + /// Specifies what, if any, separate context needs to be supplied for methods below. type Ctxt; @@ -359,7 +375,7 @@ pub trait BitDenotation { /// (Typically this should only modify `sets.on_entry`, since the /// gen and kill sets should reflect the effects of *executing* /// the start block itself.) - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets); + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets); /// Mutates the block-sets (the flow sets for the given /// basic block) according to the effects of evaluating statement. @@ -373,7 +389,7 @@ pub trait BitDenotation { /// in the basic block. fn statement_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, idx_stmt: usize); @@ -393,7 +409,7 @@ pub trait BitDenotation { /// terminator took. fn terminator_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, idx_term: usize); @@ -411,21 +427,17 @@ pub trait BitDenotation { /// flow-dependent, the current MIR cannot encode them via just /// GEN and KILL sets attached to the block, and so instead we add /// this extra machinery to represent the flow-dependent effect. - /// - /// Note: as a historical artifact, this currently takes as input - /// the *entire* packed collection of bitvectors in `in_out`. We - /// might want to look into narrowing that to something more - /// specific, just to make the interface more self-documenting. fn propagate_call_return(&self, ctxt: &Self::Ctxt, - in_out: &mut [usize], + in_out: &mut IdxSet, call_bb: repr::BasicBlock, dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue); } impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> - where D: BitDenotation + DataflowOperator, D::Ctxt: HasMoveData<'tcx> + where D: BitDenotation + DataflowOperator, + D::Ctxt: HasMoveData<'tcx> { pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, @@ -434,33 +446,41 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> let bits_per_block = denotation.bits_per_block(&ctxt); let usize_bits = mem::size_of::() * 8; let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits; - let num_blocks = mir.basic_blocks.len(); - let num_words = num_blocks * words_per_block; - let entry = if D::bottom_value() { usize::MAX } else {0}; + // (now rounded up to multiple of word size) + let bits_per_block = words_per_block * usize_bits; - let zeroes = Bits::new(0, num_words); - let on_entry = Bits::new(entry, num_words); + let num_blocks = mir.basic_blocks.len(); + let num_overall = num_blocks * bits_per_block; - DataflowAnalysis { flow_state: DataflowState { - sets: AllSets { - bits_per_block: bits_per_block, - words_per_block: words_per_block, - gen_sets: zeroes.clone(), - kill_sets: zeroes, - on_entry_sets: on_entry, + let zeroes = Bits::new(OwnIdxSet::new_empty(num_overall)); + let on_entry = Bits::new(if D::bottom_value() { + OwnIdxSet::new_filled(num_overall) + } else { + OwnIdxSet::new_empty(num_overall) + }); + + DataflowAnalysis { + ctxt: ctxt, + mir: mir, + flow_state: DataflowState { + sets: AllSets { + bits_per_block: bits_per_block, + words_per_block: words_per_block, + gen_sets: zeroes.clone(), + kill_sets: zeroes, + on_entry_sets: on_entry, + }, + operator: denotation, }, - operator: denotation, - }, - ctxt: ctxt, - mir: mir, } } } impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> - where D: BitDenotation + DataflowOperator, D::Ctxt: HasMoveData<'tcx> + where D: BitDenotation + DataflowOperator, + D::Ctxt: HasMoveData<'tcx>, { /// Propagates the bits of `in_out` into all the successors of `bb`, /// using bitwise operator denoted by `self.operator`. @@ -477,7 +497,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> /// unwind target). fn propagate_bits_into_graph_successors_of( &mut self, - in_out: &mut [usize], + in_out: &mut IdxSet, changed: &mut bool, (bb, bb_data): (repr::BasicBlock, &repr::BasicBlockData)) { @@ -518,11 +538,13 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> } fn propagate_bits_into_entry_set_for(&mut self, - in_out: &[usize], + in_out: &IdxSet, changed: &mut bool, bb: &repr::BasicBlock) { let entry_set = self.flow_state.sets.for_block(bb.index()).on_entry; - let set_changed = bitwise(entry_set, in_out, &self.flow_state.operator); + let set_changed = bitwise(entry_set.words_mut(), + in_out.words(), + &self.flow_state.operator); if set_changed { *changed = true; } @@ -694,6 +716,7 @@ pub struct MovingOutStatements<'a, 'tcx: 'a> { } impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { + type Idx = MoveOutIndex; type Bit = MoveOut; type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); fn name() -> &'static str { "moving_out" } @@ -703,13 +726,13 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { &ctxt.2.moves[idx] } - fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { + fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { // no move-statements have been executed prior to function // execution, so this method has no effect on `_sets`. } fn statement_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, idx: usize) { let &(tcx, mir, ref move_data) = ctxt; @@ -725,7 +748,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { // Every path deinitialized by a *particular move* // has corresponding bit, "gen'ed" (i.e. set) // here, in dataflow vector - zero_to_one(&mut sets.gen_set, *move_index); + zero_to_one(sets.gen_set.words_mut(), *move_index); } let bits_per_block = self.bits_per_block(ctxt); match stmt.kind { @@ -740,7 +763,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { move_path_index, |mpi| for moi in &path_map[mpi] { assert!(moi.idx() < bits_per_block); - sets.kill_set.set_bit(moi.idx()); + sets.kill_set.add(&moi); }); } } @@ -748,7 +771,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { fn terminator_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, statements_len: usize) { @@ -761,13 +784,13 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { let bits_per_block = self.bits_per_block(ctxt); for move_index in &loc_map[loc] { assert!(move_index.idx() < bits_per_block); - zero_to_one(&mut sets.gen_set, *move_index); + zero_to_one(sets.gen_set.words_mut(), *move_index); } } fn propagate_call_return(&self, ctxt: &Self::Ctxt, - in_out: &mut [usize], + in_out: &mut IdxSet, _call_bb: repr::BasicBlock, _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { @@ -782,63 +805,46 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { move_path_index, |mpi| for moi in &path_map[mpi] { assert!(moi.idx() < bits_per_block); - in_out.clear_bit(moi.idx()); + in_out.remove(&moi); }); } } impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { - fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, state: super::DropFlagState) { match state { - DropFlagState::Absent => { - sets.gen_set.clear_bit(path.idx()); - sets.kill_set.set_bit(path.idx()); - } - DropFlagState::Present => { - sets.gen_set.set_bit(path.idx()); - sets.kill_set.clear_bit(path.idx()); - } + DropFlagState::Absent => sets.kill(&path), + DropFlagState::Present => sets.gen(&path), } } } impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { - fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, state: super::DropFlagState) { match state { - DropFlagState::Absent => { - sets.gen_set.set_bit(path.idx()); - sets.kill_set.clear_bit(path.idx()); - } - DropFlagState::Present => { - sets.gen_set.clear_bit(path.idx()); - sets.kill_set.set_bit(path.idx()); - } + DropFlagState::Absent => sets.gen(&path), + DropFlagState::Present => sets.kill(&path), } } } impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { - fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, state: super::DropFlagState) { match state { - DropFlagState::Absent => { - sets.gen_set.clear_bit(path.idx()); - sets.kill_set.set_bit(path.idx()); - } - DropFlagState::Present => { - sets.gen_set.set_bit(path.idx()); - sets.kill_set.clear_bit(path.idx()); - } + DropFlagState::Absent => sets.kill(&path), + DropFlagState::Present => sets.gen(&path), } } } impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { + type Idx = MovePathIndex; type Bit = MovePath<'tcx>; type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); fn name() -> &'static str { "maybe_init" } @@ -848,19 +854,19 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { &ctxt.2.move_paths[MovePathIndex::new(idx)] } - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { super::drop_flag_effects_for_function_entry( ctxt.0, ctxt.1, &ctxt.2, |path, s| { assert!(s == DropFlagState::Present); - sets.on_entry.set_bit(path.idx()); + sets.on_entry.add(&path); }); } fn statement_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, idx: usize) { @@ -873,7 +879,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn terminator_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, statements_len: usize) { @@ -886,7 +892,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, ctxt: &Self::Ctxt, - in_out: &mut [usize], + in_out: &mut IdxSet, _call_bb: repr::BasicBlock, _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { @@ -897,12 +903,13 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { super::on_all_children_bits( ctxt.0, ctxt.1, &ctxt.2, move_path_index, - |mpi| { in_out.set_bit(mpi.idx()); } + |mpi| { in_out.add(&mpi); } ); } } impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { + type Idx = MovePathIndex; type Bit = MovePath<'tcx>; type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); fn name() -> &'static str { "maybe_uninit" } @@ -914,21 +921,21 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { } // sets on_entry bits for Arg lvalues - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { // set all bits to 1 (uninit) before gathering counterevidence - for e in &mut sets.on_entry[..] { *e = !0; } + for e in sets.on_entry.words_mut() { *e = !0; } super::drop_flag_effects_for_function_entry( ctxt.0, ctxt.1, &ctxt.2, |path, s| { assert!(s == DropFlagState::Present); - sets.on_entry.clear_bit(path.idx()); + sets.on_entry.remove(&path); }); } fn statement_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, idx: usize) { @@ -941,7 +948,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { fn terminator_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, statements_len: usize) { @@ -954,7 +961,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, ctxt: &Self::Ctxt, - in_out: &mut [usize], + in_out: &mut IdxSet, _call_bb: repr::BasicBlock, _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { @@ -964,12 +971,13 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { super::on_all_children_bits( ctxt.0, ctxt.1, &ctxt.2, move_path_index, - |mpi| { in_out.clear_bit(mpi.idx()); } + |mpi| { in_out.remove(&mpi); } ); } } impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { + type Idx = MovePathIndex; type Bit = MovePath<'tcx>; type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); fn name() -> &'static str { "definite_init" } @@ -981,20 +989,20 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { } // sets on_entry bits for Arg lvalues - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { - for e in &mut sets.on_entry[..] { *e = 0; } + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { + for e in sets.on_entry.words_mut() { *e = 0; } super::drop_flag_effects_for_function_entry( ctxt.0, ctxt.1, &ctxt.2, |path, s| { assert!(s == DropFlagState::Present); - sets.on_entry.set_bit(path.idx()); + sets.on_entry.add(&path); }); } fn statement_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, idx: usize) { @@ -1007,7 +1015,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { fn terminator_effect(&self, ctxt: &Self::Ctxt, - sets: &mut BlockSets, + sets: &mut BlockSets, bb: repr::BasicBlock, statements_len: usize) { @@ -1020,7 +1028,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, ctxt: &Self::Ctxt, - in_out: &mut [usize], + in_out: &mut IdxSet, _call_bb: repr::BasicBlock, _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { @@ -1030,7 +1038,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { super::on_all_children_bits( ctxt.0, ctxt.1, &ctxt.2, move_path_index, - |mpi| { in_out.set_bit(mpi.idx()); } + |mpi| { in_out.add(&mpi); } ); } } @@ -1106,26 +1114,3 @@ impl<'a, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'tcx> { } } -#[inline] -fn bitwise(out_vec: &mut [usize], - in_vec: &[usize], - op: &Op) -> bool { - assert_eq!(out_vec.len(), in_vec.len()); - let mut changed = false; - for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) { - let old_val = *out_elt; - let new_val = op.join(old_val, *in_elt); - *out_elt = new_val; - changed |= old_val != new_val; - } - changed -} - -struct Union; -impl BitwiseOperator for Union { - fn join(&self, a: usize, b: usize) -> usize { a | b } -} -struct Subtract; -impl BitwiseOperator for Subtract { - fn join(&self, a: usize, b: usize) -> usize { a & !b } -} diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 7c8a9a4aeb0f..6cf20def0e0c 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -15,10 +15,7 @@ use syntax::codemap::Span; use rustc::ty::{self, TyCtxt}; use rustc::mir::repr::{self, Mir}; -use bitslice::BitSlice; - -use super::super::gather_moves::MovePath; -use super::{bitwise, Union, Subtract}; +use super::super::gather_moves::{MovePath, MovePathIndex}; use super::BitDenotation; use super::DataflowResults; use super::HasMoveData; @@ -45,7 +42,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _attributes: &[ast::Attribute], flow_ctxt: &O::Ctxt, results: &DataflowResults) - where O: BitDenotation>, O::Ctxt: HasMoveData<'tcx> + where O: BitDenotation, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx> { debug!("sanity_check_via_rustc_peek id: {:?}", id); // FIXME: this is not DRY. Figure out way to abstract this and @@ -87,9 +84,9 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // include terminator (since we are peeking the state of the // argument at time immediate preceding Call to `rustc_peek`). - let mut sets = super::BlockSets { on_entry: &mut entry[..], - gen_set: &mut gen[..], - kill_set: &mut kill[..] }; + let mut sets = super::BlockSets { on_entry: &mut entry, + gen_set: &mut gen, + kill_set: &mut kill }; for (j, stmt) in statements.iter().enumerate() { debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); @@ -105,7 +102,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ref peeking_at_lval) = *rvalue { // Okay, our search is over. let peek_mpi = move_data.rev_lookup.find(peeking_at_lval); - let bit_state = sets.on_entry.get_bit(peek_mpi.idx()); + let bit_state = sets.on_entry.contains(&peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", lvalue, peeking_at_lval, bit_state); if !bit_state { @@ -126,11 +123,11 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}", lvalue, lhs_mpi, stmt); // reset GEN and KILL sets before emulating their effect. - for e in &mut sets.gen_set[..] { *e = 0; } - for e in &mut sets.kill_set[..] { *e = 0; } + for e in sets.gen_set.words_mut() { *e = 0; } + for e in sets.kill_set.words_mut() { *e = 0; } results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j); - bitwise(sets.on_entry, sets.gen_set, &Union); - bitwise(sets.on_entry, sets.kill_set, &Subtract); + sets.on_entry.union(sets.gen_set); + sets.on_entry.subtract(sets.kill_set); } tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 519e9398436b..e196de46ee67 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -20,6 +20,7 @@ use std::iter; use std::ops::Index; use super::abs_domain::{AbstractElem, Lift}; +use indexed_set::{Idx, Indexed}; // This submodule holds some newtype'd Index wrappers that are using // NonZero to ensure that Option occupies only a single word. @@ -28,6 +29,7 @@ use super::abs_domain::{AbstractElem, Lift}; // (which is likely to yield a subtle off-by-one error). mod indexes { use core::nonzero::NonZero; + use indexed_set::Idx; macro_rules! new_index { ($Index:ident) => { @@ -35,10 +37,13 @@ mod indexes { pub struct $Index(NonZero); impl $Index { - pub fn new(idx: usize) -> Self { + } + + impl Idx for $Index { + fn new(idx: usize) -> Self { unsafe { $Index(NonZero::new(idx + 1)) } } - pub fn idx(&self) -> usize { + fn idx(&self) -> usize { *self.0 - 1 } } @@ -55,6 +60,14 @@ mod indexes { pub use self::indexes::MovePathIndex; pub use self::indexes::MoveOutIndex; +impl<'tcx> Indexed for MovePath<'tcx> { + type Idx = MovePathIndex; +} + +impl Indexed for MoveOut { + type Idx = MoveOutIndex; +} + impl self::indexes::MoveOutIndex { pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex { move_data.moves[self.idx()].path diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs index c743e58aa996..c37f8e09e0ac 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_borrowck/indexed_set.rs @@ -11,13 +11,16 @@ use std::fmt; use std::marker::PhantomData; use std::mem; +use std::ops::{Deref, DerefMut, Range}; use bitslice::{BitSlice, Word}; +use bitslice::{bitwise, Union, Subtract}; pub trait Indexed { type Idx: Idx; } -pub trait Idx { +pub trait Idx: 'static { + fn new(usize) -> Self; fn idx(&self) -> usize; } @@ -26,10 +29,16 @@ pub struct OwnIdxSet { bits: Vec, } +impl Clone for OwnIdxSet { + fn clone(&self) -> Self { + OwnIdxSet { _pd: PhantomData, bits: self.bits.clone() } + } +} + // pnkfelix wants to have this be `IdxSet([Word]) and then pass // around `&mut IdxSet` or `&IdxSet`. // -// Mmapping a `&OwnIdxSet` to `&IdxSet` (at least today) +// WARNING: Mapping a `&OwnIdxSet` to `&IdxSet` (at least today) // requires a transmute relying on representation guarantees that may // not hold in the future. @@ -65,9 +74,41 @@ impl OwnIdxSet { pub fn new_empty(universe_size: usize) -> Self { Self::new(0, universe_size) } +} + +impl IdxSet { + unsafe fn from_slice(s: &[Word]) -> &Self { + mem::transmute(s) // (see above WARNING) + } + + unsafe fn from_slice_mut(s: &mut [Word]) -> &mut Self { + mem::transmute(s) // (see above WARNING) + } +} + +impl Deref for OwnIdxSet { + type Target = IdxSet; + fn deref(&self) -> &IdxSet { + unsafe { IdxSet::from_slice(&self.bits[..]) } + } +} + +impl DerefMut for OwnIdxSet { + fn deref_mut(&mut self) -> &mut IdxSet { + unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) } + } +} + +impl IdxSet { + pub fn to_owned(&self) -> OwnIdxSet { + OwnIdxSet { + _pd: Default::default(), + bits: self.bits.to_owned(), + } + } /// Removes `elem` from the set `self`; returns true iff this changed `self`. - pub fn clear(&mut self, elem: &T) -> bool { + pub fn remove(&mut self, elem: &T) -> bool { self.bits.clear_bit(elem.idx()) } @@ -76,12 +117,38 @@ impl OwnIdxSet { self.bits.set_bit(elem.idx()) } + pub fn range(&self, elems: &Range) -> &Self { + let elems = elems.start.idx()..elems.end.idx(); + unsafe { Self::from_slice(&self.bits[elems]) } + } + + pub fn range_mut(&mut self, elems: &Range) -> &mut Self { + let elems = elems.start.idx()..elems.end.idx(); + unsafe { Self::from_slice_mut(&mut self.bits[elems]) } + } + /// Returns true iff set `self` contains `elem`. pub fn contains(&self, elem: &T) -> bool { self.bits.get_bit(elem.idx()) } - pub fn bits(&self) -> &[Word] { + pub fn words(&self) -> &[Word] { &self.bits[..] } + + pub fn words_mut(&mut self) -> &mut [Word] { + &mut self.bits[..] + } + + pub fn clone_from(&mut self, other: &IdxSet) { + self.words_mut().clone_from_slice(other.words()); + } + + pub fn union(&mut self, other: &IdxSet) -> bool { + bitwise(self.words_mut(), other.words(), &Union) + } + + pub fn subtract(&mut self, other: &IdxSet) -> bool { + bitwise(self.words_mut(), other.words(), &Subtract) + } } From e59bb79007a9b7b4468f44fe48ac1a7d949430c0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 23 May 2016 09:49:46 -0700 Subject: [PATCH 080/179] bootstrap: rename Config.rebuild to .local_rebuild --- src/bootstrap/build/config.rs | 4 ++-- src/bootstrap/build/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/build/config.rs b/src/bootstrap/build/config.rs index 060fb5b8ef3d..fb1ad12d914f 100644 --- a/src/bootstrap/build/config.rs +++ b/src/bootstrap/build/config.rs @@ -67,7 +67,7 @@ pub struct Config { pub target: Vec, pub rustc: Option, pub cargo: Option, - pub rebuild: bool, + pub local_rebuild: bool, // libstd features pub debug_jemalloc: bool, @@ -316,7 +316,7 @@ impl Config { ("RPATH", self.rust_rpath), ("OPTIMIZE_TESTS", self.rust_optimize_tests), ("DEBUGINFO_TESTS", self.rust_debuginfo_tests), - ("LOCAL_REBUILD", self.rebuild), + ("LOCAL_REBUILD", self.local_rebuild), } match key { diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs index 9d5a093ab9e0..21d12d27d92e 100644 --- a/src/bootstrap/build/mod.rs +++ b/src/bootstrap/build/mod.rs @@ -511,7 +511,7 @@ impl Build { .arg("--target").arg(target); let stage; - if compiler.stage == 0 && self.config.rebuild { + if compiler.stage == 0 && self.config.local_rebuild { // Assume the local-rebuild rustc already has stage1 features. stage = 1; } else { @@ -752,7 +752,7 @@ impl Build { // In stage0 we're using a previously released stable compiler, so we // use the stage0 bootstrap key. Otherwise we use our own build's // bootstrap key. - let bootstrap_key = if compiler.is_snapshot(self) && !self.config.rebuild { + let bootstrap_key = if compiler.is_snapshot(self) && !self.config.local_rebuild { &self.bootstrap_key_stage0 } else { &self.bootstrap_key From 7f874635ca1fb4a8617a737b80358a955ba49443 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 23 May 2016 12:50:34 -0400 Subject: [PATCH 081/179] Update error format for readability. Add spacing header<->snippet and another line between errors --- src/libsyntax/errors/emitter.rs | 2 +- src/libsyntax/errors/snippet/mod.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 7c9985d7d233..2ba003c5eafb 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -238,7 +238,7 @@ impl EmitterWriter { self.first = false; } else { if !self.old_school { - write!(self.dst, "\n")?; + write!(self.dst, "\n\n")?; } } } diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 188e676e7dff..414da87b749c 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -478,6 +478,13 @@ impl FileInfo { }], kind: RenderedLineKind::PrimaryFileName, }); + output.push(RenderedLine { + text: vec![StyledString { + text: "".to_string(), + style: Style::FileNameStyle, + }], + kind: RenderedLineKind::Annotations, + }); } None => { output.push(RenderedLine { From bb6ea4fb15f873f98e8d4e18e44884e1d3cc9e7e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 12:52:38 -0400 Subject: [PATCH 082/179] Shorten, yet clarify, initial summary sentences --- src/libcore/clone.rs | 4 +++- src/libcore/default.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 629808cb1243..3a5ba2387ac2 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -46,7 +46,9 @@ use marker::Sized; -/// A common trait for cloning an object. Differs from `Copy` in that you can +/// A common trait for the ability to explicitly duplicate an object. +/// +/// Differs from `Copy` in that you can /// define `Clone` to run arbitrary code, while you are not allowed to override /// the implementation of `Copy` that only does a `memcpy`. /// diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 74101c66c97a..689ace97e232 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -84,7 +84,9 @@ use marker::Sized; -/// A trait for giving a type a useful default value. For more information, see +/// A trait for giving a type a useful default value. +/// +/// For more information, see /// [the module-level documentation][module]. /// /// [module]: ../../std/default/index.html From 0a26fbc19f7fd058732ddc1202ac9a41864e7a09 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 12:58:42 -0400 Subject: [PATCH 083/179] Emphasize semantic differences of Copy/Clone rather than impl --- src/libcore/clone.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 3a5ba2387ac2..82097c6b5e78 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -48,9 +48,10 @@ use marker::Sized; /// A common trait for the ability to explicitly duplicate an object. /// -/// Differs from `Copy` in that you can -/// define `Clone` to run arbitrary code, while you are not allowed to override -/// the implementation of `Copy` that only does a `memcpy`. +/// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while +/// `Clone` is always explicit and may or may not be expensive. In order to enforce +/// these characteristics, Rust does not allow you to reimplement `Copy`, but you +/// may reimplement `Clone` and run arbitrary code. /// /// Since `Clone` is more general than `Copy`, you can automatically make anything /// `Copy` be `Clone` as well. From bd113943e6e29dd57074b9d29b13378a02d84b58 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 13:00:01 -0400 Subject: [PATCH 084/179] "more than 32" => "more than 32 elements" --- src/libcore/clone.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 82097c6b5e78..489aa66885fc 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -68,8 +68,8 @@ use marker::Sized; /// Manual implementations should be careful to uphold this invariant; however, unsafe code /// must not rely on it to ensure memory safety. /// -/// An example is an array holding more than 32 of a type that is `Clone`; the standard library -/// only implements `Clone` up until arrays of size 32. In this case, the implementation of +/// An example is an array holding more than 32 elements of a type that is `Clone`; the standard +/// library only implements `Clone` up until arrays of size 32. In this case, the implementation of /// `Clone` cannot be `derive`d, but can be implemented as: /// /// ``` From 572b5e462f091bb26f8d7a04c512898275e30b6c Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 24 May 2016 02:00:39 +0900 Subject: [PATCH 085/179] Remove unused field and argument --- src/librustc_driver/driver.rs | 1 - src/libsyntax/test.rs | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2965c763ccc4..34527d1689c0 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -745,7 +745,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, sess.opts.test, - &sess.opts.cfg, krate, sess.diagnostic()) }); diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 56485433101f..6785a8690d47 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -59,7 +59,6 @@ struct TestCtxt<'a> { testfns: Vec, reexport_test_harness_main: Option, is_test_crate: bool, - config: ast::CrateConfig, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -69,7 +68,6 @@ struct TestCtxt<'a> { // existing main functions, and synthesizing a main test harness pub fn modify_for_testing(sess: &ParseSess, should_test: bool, - cfg: &ast::CrateConfig, krate: ast::Crate, span_diagnostic: &errors::Handler) -> ast::Crate { // Check for #[reexport_test_harness_main = "some_name"] which @@ -81,7 +79,7 @@ pub fn modify_for_testing(sess: &ParseSess, "reexport_test_harness_main"); if should_test { - generate_test_harness(sess, reexport_test_harness_main, krate, cfg, span_diagnostic) + generate_test_harness(sess, reexport_test_harness_main, krate, span_diagnostic) } else { strip_test_functions(span_diagnostic, krate) } @@ -267,7 +265,6 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, fn generate_test_harness(sess: &ParseSess, reexport_test_harness_main: Option, krate: ast::Crate, - cfg: &ast::CrateConfig, sd: &errors::Handler) -> ast::Crate { // Remove the entry points let mut cleaner = EntryPointCleaner { depth: 0 }; @@ -277,14 +274,13 @@ fn generate_test_harness(sess: &ParseSess, let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, cfg.clone(), + ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), &mut feature_gated_cfgs), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, is_test_crate: is_test_crate(&krate), - config: krate.config.clone(), toplevel_reexport: None, }; cx.ext_cx.crate_root = Some("std"); From 9a64fa021df856891d8abc6354f38493935590c7 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 13:02:16 -0400 Subject: [PATCH 086/179] "non equal" => "not equal"; consistent with the surrounding text --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 5b8620f4b8eb..f26a6dad8800 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -56,7 +56,7 @@ use option::Option::{self, Some}; /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d on structs, two -/// instances are equal if all fields are equal, and non equal if any fields +/// instances are equal if all fields are equal, and not equal if any fields /// are not equal. When `derive`d on enums, each variant is equal to itself /// and not equal to the other variants. /// From 510bfcb3d4036594481787e6e3021167a76ea395 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 13:04:05 -0400 Subject: [PATCH 087/179] Add some newlines in some code examples --- src/libcore/cmp.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index f26a6dad8800..be56ab1a41b8 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -76,6 +76,7 @@ use option::Option::{self, Some}; /// isbn: i32, /// format: BookFormat, /// } +/// /// impl PartialEq for Book { /// fn eq(&self, other: &Self) -> bool { /// self.isbn == other.isbn @@ -262,6 +263,7 @@ impl Ordering { /// /// ``` /// use std::cmp::Ordering; +/// /// #[derive(Eq)] /// struct Person { /// id: u32, From 562b122bd44e51706680c36d9a099562e18f8645 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 13:06:23 -0400 Subject: [PATCH 088/179] Use `()` when referring to functions --- src/libcore/cmp.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index be56ab1a41b8..f23128b33646 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -255,8 +255,8 @@ impl Ordering { /// /// `Ord` requires that the type also be `PartialOrd` and `Eq` (which requires `PartialEq`). /// -/// Then you must define an implementation for `cmp`. You may find it useful to use -/// `cmp` on your type's fields. +/// Then you must define an implementation for `cmp()`. You may find it useful to use +/// `cmp()` on your type's fields. /// /// Here's an example where you want to sort people by height only, disregarding `id` /// and `name`: @@ -355,7 +355,7 @@ impl PartialOrd for Ordering { /// /// `PartialOrd` requires your type to be `PartialEq`. /// -/// If your type is `Ord`, you can implement `partial_cmp` by using `cmp`: +/// If your type is `Ord`, you can implement `partial_cmp()` by using `cmp()`: /// /// ``` /// impl PartialOrd for Person { @@ -365,7 +365,7 @@ impl PartialOrd for Ordering { /// } /// ``` /// -/// You may also find it useful to use `partial_cmp` on your type`s fields. Here +/// You may also find it useful to use `partial_cmp()` on your type`s fields. Here /// is an example of `Person` types who have a floating-point `height` field that /// is the only field to be used for sorting: /// From c8a4cf1cf071d376e162867aaefbedd8745055da Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 13:13:09 -0400 Subject: [PATCH 089/179] Prefer `ClassName` over `Self` in example trait implementations --- src/libcore/clone.rs | 2 +- src/libcore/cmp.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 489aa66885fc..e8cd36f3cd70 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -79,7 +79,7 @@ use marker::Sized; /// } /// /// impl Clone for Stats { -/// fn clone(&self) -> Self { *self } +/// fn clone(&self) -> Stats { *self } /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index f23128b33646..5b289fd1e005 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -78,7 +78,7 @@ use option::Option::{self, Some}; /// } /// /// impl PartialEq for Book { -/// fn eq(&self, other: &Self) -> bool { +/// fn eq(&self, other: &Book) -> bool { /// self.isbn == other.isbn /// } /// } @@ -147,7 +147,7 @@ pub trait PartialEq { /// format: BookFormat, /// } /// impl PartialEq for Book { -/// fn eq(&self, other: &Self) -> bool { +/// fn eq(&self, other: &Book) -> bool { /// self.isbn == other.isbn /// } /// } @@ -272,19 +272,19 @@ impl Ordering { /// } /// /// impl Ord for Person { -/// fn cmp(&self, other: &Self) -> Ordering { +/// fn cmp(&self, other: &Person) -> Ordering { /// self.height.cmp(&other.height) /// } /// } /// /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Self) -> Option { +/// fn partial_cmp(&self, other: &Person) -> Option { /// Some(self.cmp(other)) /// } /// } /// /// impl PartialEq for Person { -/// fn eq(&self, other: &Self) -> bool { +/// fn eq(&self, other: &Person) -> bool { /// self.height == other.height /// } /// } @@ -359,7 +359,7 @@ impl PartialOrd for Ordering { /// /// ``` /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Self) -> Option { +/// fn partial_cmp(&self, other: &Person) -> Option { /// Some(self.cmp(other)) /// } /// } @@ -379,13 +379,13 @@ impl PartialOrd for Ordering { /// } /// /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Self) -> Option { +/// fn partial_cmp(&self, other: &Person) -> Option { /// self.height.partial_cmp(&other.height) /// } /// } /// /// impl PartialEq for Person { -/// fn eq(&self, other: &Self) -> bool { +/// fn eq(&self, other: &Person) -> bool { /// self.height == other.height /// } /// } From 2cb36146e8b3c9cec028fdfa4381578e8516abe0 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 13:47:28 -0400 Subject: [PATCH 090/179] Move all `Default` docs from module to trait I had already copied the implementation example in a previous commit; this copies the explanation and usage examples to the general trait description. --- src/libcore/default.rs | 115 +++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 73 deletions(-) diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 689ace97e232..485ddae07fbf 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -9,76 +9,6 @@ // except according to those terms. //! The `Default` trait for types which may have meaningful default values. -//! -//! Sometimes, you want to fall back to some kind of default value, and -//! don't particularly care what it is. This comes up often with `struct`s -//! that define a set of options: -//! -//! ``` -//! # #[allow(dead_code)] -//! struct SomeOptions { -//! foo: i32, -//! bar: f32, -//! } -//! ``` -//! -//! How can we define some default values? You can use `Default`: -//! -//! ``` -//! # #[allow(dead_code)] -//! #[derive(Default)] -//! struct SomeOptions { -//! foo: i32, -//! bar: f32, -//! } -//! -//! -//! fn main() { -//! let options: SomeOptions = Default::default(); -//! } -//! ``` -//! -//! Now, you get all of the default values. Rust implements `Default` for various primitives types. -//! If you have your own type, you need to implement `Default` yourself: -//! -//! ``` -//! # #![allow(dead_code)] -//! enum Kind { -//! A, -//! B, -//! C, -//! } -//! -//! impl Default for Kind { -//! fn default() -> Kind { Kind::A } -//! } -//! -//! #[derive(Default)] -//! struct SomeOptions { -//! foo: i32, -//! bar: f32, -//! baz: Kind, -//! } -//! -//! -//! fn main() { -//! let options: SomeOptions = Default::default(); -//! } -//! ``` -//! -//! If you want to override a particular option, but still retain the other defaults: -//! -//! ``` -//! # #[allow(dead_code)] -//! # #[derive(Default)] -//! # struct SomeOptions { -//! # foo: i32, -//! # bar: f32, -//! # } -//! fn main() { -//! let options = SomeOptions { foo: 42, ..Default::default() }; -//! } -//! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -86,10 +16,49 @@ use marker::Sized; /// A trait for giving a type a useful default value. /// -/// For more information, see -/// [the module-level documentation][module]. +/// Sometimes, you want to fall back to some kind of default value, and +/// don't particularly care what it is. This comes up often with `struct`s +/// that define a set of options: /// -/// [module]: ../../std/default/index.html +/// ``` +/// # #[allow(dead_code)] +/// struct SomeOptions { +/// foo: i32, +/// bar: f32, +/// } +/// ``` +/// +/// How can we define some default values? You can use `Default`: +/// +/// ``` +/// # #[allow(dead_code)] +/// #[derive(Default)] +/// struct SomeOptions { +/// foo: i32, +/// bar: f32, +/// } +/// +/// +/// fn main() { +/// let options: SomeOptions = Default::default(); +/// } +/// ``` +/// +/// Now, you get all of the default values. Rust implements `Default` for various primitives types. +/// +/// If you want to override a particular option, but still retain the other defaults: +/// +/// ``` +/// # #[allow(dead_code)] +/// # #[derive(Default)] +/// # struct SomeOptions { +/// # foo: i32, +/// # bar: f32, +/// # } +/// fn main() { +/// let options = SomeOptions { foo: 42, ..Default::default() }; +/// } +/// ``` /// /// ## Derivable /// From 0d749d6e5dbfbd818fd0d178072aff7a34b28587 Mon Sep 17 00:00:00 2001 From: Nick Hamann Date: Tue, 17 May 2016 02:59:18 -0500 Subject: [PATCH 091/179] Improve the long explanation of E0207. The previous explanation does not seem to explain what it means for an implementation parameter to be used or unused. The new explanation lists the three ways specific ways by which an impl parameter becomes constrained (taken from RFC 447). This also adds a link to RFC 447. The explanation has two different examples. The first is adapted from RFC 447, and shows an instance of E0207 on a impl for a type. The second one is a trait impl example adapted from issue #22834. Closes #33650 --- src/librustc_typeck/diagnostics.rs | 126 +++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index dbdbd32372a4..40b9b0e01ab9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2387,39 +2387,135 @@ impl Copy for &'static Bar { } // error "##, E0207: r##" -You declared an unused type parameter when implementing a trait on an object. -Erroneous code example: +Any type parameter or lifetime parameter of an `impl` must meet at least one of +the following criteria: + + - it appears in the self type of the impl + - for a trait impl, it appears in the trait reference + - it is bound as an associated type + +### Error example 1 + +Suppose we have a struct `Foo` and we would like to define some methods for it. +The following definition leads to a compiler error: ```compile_fail -trait MyTrait { - fn get(&self) -> usize; +struct Foo; + +impl Foo { +// error: the type parameter `T` is not constrained by the impl trait, self +// type, or predicates [E0207] + fn get(&self) -> T { + ::default() + } } +``` + +The problem is that the parameter `T` does not appear in the self type (`Foo`) +of the impl. In this case, we can fix the error by moving the type parameter +from the `impl` to the method `get`: + +``` struct Foo; -impl MyTrait for Foo { - fn get(&self) -> usize { - 0 +// Move the type parameter from the impl to the method +impl Foo { + fn get(&self) -> T { + ::default() } } ``` -Please check your object definition and remove unused type -parameter(s). Example: +### Error example 2 +As another example, suppose we have a `Maker` trait and want to establish a +type `FooMaker` that makes `Foo`s: + +```compile_fail +trait Maker { + type Item; + fn make(&mut self) -> Self::Item; +} + +struct Foo { + foo: T +} + +struct FooMaker; + +impl Maker for FooMaker { +// error: the type parameter `T` is not constrained by the impl trait, self +// type, or predicates [E0207] + type Item = Foo; + + fn make(&mut self) -> Foo { + Foo { foo: ::default() } + } +} ``` -trait MyTrait { - fn get(&self) -> usize; + +This fails to compile because `T` does not appear in the trait or in the +implementing type. + +One way to work around this is to introduce a phantom type parameter into +`FooMaker`, like so: + +``` +use std::marker::PhantomData; + +trait Maker { + type Item; + fn make(&mut self) -> Self::Item; } -struct Foo; +struct Foo { + foo: T +} -impl MyTrait for Foo { - fn get(&self) -> usize { - 0 +// Add a type parameter to `FooMaker` +struct FooMaker { + phantom: PhantomData, +} + +impl Maker for FooMaker { + type Item = Foo; + + fn make(&mut self) -> Foo { + Foo { + foo: ::default(), + } + } +} +``` + +Another way is to do away with the associated type in `Maker` and use an input +type parameter instead: + +``` +// Use a type parameter instead of an associated type here +trait Maker { + fn make(&mut self) -> Item; +} + +struct Foo { + foo: T +} + +struct FooMaker; + +impl Maker> for FooMaker { + fn make(&mut self) -> Foo { + Foo { foo: ::default() } } } ``` + +### Additional information + +For more information, please see [RFC 447]. + +[RFC 447]: https://github.com/rust-lang/rfcs/blob/master/text/0447-no-unused-impl-parameters.md "##, E0210: r##" From 0112221d94b4e401422e2e3f559f1f7637a0860e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 14:07:58 -0400 Subject: [PATCH 092/179] Complete `PartialOrd`'s example so it passes make check-docs --- src/libcore/cmp.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 5b289fd1e005..8764766b2ef8 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -358,11 +358,32 @@ impl PartialOrd for Ordering { /// If your type is `Ord`, you can implement `partial_cmp()` by using `cmp()`: /// /// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(Eq)] +/// struct Person { +/// id: u32, +/// name: String, +/// height: u32, +/// } +/// /// impl PartialOrd for Person { /// fn partial_cmp(&self, other: &Person) -> Option { /// Some(self.cmp(other)) /// } /// } +/// +/// impl Ord for Person { +/// fn cmp(&self, other: &Person) -> Ordering { +/// self.height.cmp(&other.height) +/// } +/// } +/// +/// impl PartialEq for Person { +/// fn eq(&self, other: &Person) -> bool { +/// self.height == other.height +/// } +/// } /// ``` /// /// You may also find it useful to use `partial_cmp()` on your type`s fields. Here From 248665ce5715eff423146dfbc351d1bfa8f8aa7d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 23 May 2016 14:09:43 -0400 Subject: [PATCH 093/179] "the trait `Hash`" => "the `Hash` trait" --- src/libcore/hash/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 844a24e80d1a..051eb974895c 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -38,7 +38,7 @@ //! ``` //! //! If you need more control over how a value is hashed, you need to implement -//! the trait `Hash`: +//! the `Hash` trait: //! //! ```rust //! use std::hash::{Hash, Hasher, SipHasher}; @@ -106,7 +106,7 @@ mod sip; /// ## How can I implement `Hash`? /// /// If you need more control over how a value is hashed, you need to implement -/// the trait `Hash`: +/// the `Hash` trait: /// /// ``` /// use std::hash::{Hash, Hasher}; From 042c37ed93fcda1c83f46c9060889fbe131aa4f6 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 23 May 2016 14:48:11 -0400 Subject: [PATCH 094/179] Fix #33819 and update ui test --- src/librustc_borrowck/borrowck/mod.rs | 6 +++++- src/test/compile-fail/issue-33819.rs | 9 +++++++++ src/test/ui/mismatched_types/main.stderr | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/issue-33819.rs diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 36222e172b8d..819717628d62 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -977,7 +977,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.map.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { - if snippet != "self" { + if snippet.starts_with("ref ") { + db.span_label(span, + &format!("use `{}` here to make mutable", + snippet.replace("ref ", "ref mut "))); + } else if snippet != "self" { db.span_label(span, &format!("use `mut {}` here to make mutable", snippet)); } diff --git a/src/test/compile-fail/issue-33819.rs b/src/test/compile-fail/issue-33819.rs new file mode 100644 index 000000000000..418e66dbd4d3 --- /dev/null +++ b/src/test/compile-fail/issue-33819.rs @@ -0,0 +1,9 @@ +fn main() { + let mut op = Some(2); + match op { + Some(ref v) => { let a = &mut v; }, + //~^ ERROR:cannot borrow immutable + //~| use `ref mut v` here to make mutable + None => {}, + } +} diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 98bc11752e0e..0e68c0d0b135 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -1,8 +1,10 @@ error: mismatched types [--explain E0308] --> $DIR/main.rs:14:18 + |> 14 |> let x: u32 = ( |> ^ expected u32, found () note: expected type `u32` note: found type `()` + error: aborting due to previous error From 18350f63cfa7bc8c92e158e9a355874b09b043ca Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 May 2016 00:33:16 +0200 Subject: [PATCH 095/179] Fix invalid background color in stability elements --- src/librustdoc/html/static/styles/main.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index 59b2ff7e3d64..aa08cee13ef7 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -30,6 +30,10 @@ h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.t background-color: white; } +div.stability > em > code { + background-color: initial; +} + .docblock code { background-color: #F5F5F5; } From e65f55d4764aa9457a5ee767191f9c801df50de0 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 23 May 2016 08:19:35 +0530 Subject: [PATCH 096/179] format with [rustfmt_skip] and addressed a few comments --- src/libcollectionstest/enum_set.rs | 97 ++++++------------------------ src/libcollectionstest/slice.rs | 2 - 2 files changed, 19 insertions(+), 80 deletions(-) diff --git a/src/libcollectionstest/enum_set.rs b/src/libcollectionstest/enum_set.rs index 0702471104bd..972361326d7b 100644 --- a/src/libcollectionstest/enum_set.rs +++ b/src/libcollectionstest/enum_set.rs @@ -62,8 +62,9 @@ fn test_len() { assert_eq!(e.len(), 0); } -/// //////////////////////////////////////////////////////////////////////// -/// intersect +/////////////////////////////////////////////////////////////////////////// +// intersect + #[test] fn test_two_empties_do_not_intersect() { let e1: EnumSet = EnumSet::new(); @@ -106,8 +107,9 @@ fn test_overlapping_intersects() { assert!(!e1.is_disjoint(&e2)); } -/// //////////////////////////////////////////////////////////////////////// -/// contains and contains_elem +/////////////////////////////////////////////////////////////////////////// +// contains and contains_elem + #[test] fn test_superset() { let mut e1: EnumSet = EnumSet::new(); @@ -141,8 +143,9 @@ fn test_contains() { assert!(!e1.contains(&C)); } -/// //////////////////////////////////////////////////////////////////////// -/// iter +/////////////////////////////////////////////////////////////////////////// +// iter + #[test] fn test_iterator() { let mut e1: EnumSet = EnumSet::new(); @@ -167,8 +170,9 @@ fn test_iterator() { assert_eq!(elems, [A, B, C]); } -/// //////////////////////////////////////////////////////////////////////// -/// operators +/////////////////////////////////////////////////////////////////////////// +// operators + #[test] fn test_operators() { let mut e1: EnumSet = EnumSet::new(); @@ -219,76 +223,13 @@ fn test_overflow() { #[derive(Copy, Clone)] #[repr(usize)] enum Bar { - V00, - V01, - V02, - V03, - V04, - V05, - V06, - V07, - V08, - V09, - V10, - V11, - V12, - V13, - V14, - V15, - V16, - V17, - V18, - V19, - V20, - V21, - V22, - V23, - V24, - V25, - V26, - V27, - V28, - V29, - V30, - V31, - V32, - V33, - V34, - V35, - V36, - V37, - V38, - V39, - V40, - V41, - V42, - V43, - V44, - V45, - V46, - V47, - V48, - V49, - V50, - V51, - V52, - V53, - V54, - V55, - V56, - V57, - V58, - V59, - V60, - V61, - V62, - V63, - V64, - V65, - V66, - V67, - V68, - V69, + V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, + V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, + V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, + V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, + V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, + V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, + V60, V61, V62, V63, V64, V65, V66, V67, V68, V69, } impl CLike for Bar { diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 76d70b113f77..71416f2069fa 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -342,7 +342,6 @@ fn test_dedup_unique() { v2.dedup(); // If the boxed pointers were leaked or otherwise misused, valgrind // and/or rt should raise errors. - // } #[test] @@ -355,7 +354,6 @@ fn test_dedup_shared() { v2.dedup(); // If the pointers were leaked or otherwise misused, valgrind and/or // rt should raise errors. - // } #[test] From 87ad845f6b3e9038ee51920e3aed417ede221b43 Mon Sep 17 00:00:00 2001 From: diwic Date: Tue, 24 May 2016 07:28:32 +0200 Subject: [PATCH 097/179] panic.rs: fix docs (recover -> catch_unwind) The current docs are a bit inconsistent. First, change all references of "recover" to "catch_unwind" because the function was renamed. Second, consistently use the term "unwind safe" instead of "panic safe", "exception safe" and "recover safe" (all these terms were used previously). --- src/libstd/panic.rs | 70 ++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 3b170dc9c6d5..6770eafeac90 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -39,14 +39,14 @@ pub fn take_handler() -> Box { take_hook() } -/// A marker trait which represents "panic safe" types in Rust. +/// A marker trait which represents "unwind safe" types in Rust. /// /// This trait is implemented by default for many types and behaves similarly in /// terms of inference of implementation to the `Send` and `Sync` traits. The -/// purpose of this trait is to encode what types are safe to cross a `recover` -/// boundary with no fear of panic safety. +/// purpose of this trait is to encode what types are safe to cross a `catch_unwind` +/// boundary with no fear of unwind safety. /// -/// ## What is panic safety? +/// ## What is unwind safety? /// /// In Rust a function can "return" early if it either panics or calls a /// function which transitively panics. This sort of control flow is not always @@ -59,62 +59,62 @@ pub fn take_handler() -> Box { /// /// Typically in Rust, it is difficult to perform step (2) because catching a /// panic involves either spawning a thread (which in turns makes it difficult -/// to later witness broken invariants) or using the `recover` function in this +/// to later witness broken invariants) or using the `catch_unwind` function in this /// module. Additionally, even if an invariant is witnessed, it typically isn't a -/// problem in Rust because there's no uninitialized values (like in C or C++). +/// problem in Rust because there are no uninitialized values (like in C or C++). /// /// It is possible, however, for **logical** invariants to be broken in Rust, -/// which can end up causing behavioral bugs. Another key aspect of panic safety +/// which can end up causing behavioral bugs. Another key aspect of unwind safety /// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to /// memory unsafety. /// -/// That was a bit of a whirlwind tour of panic safety, but for more information -/// about panic safety and how it applies to Rust, see an [associated RFC][rfc]. +/// That was a bit of a whirlwind tour of unwind safety, but for more information +/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc]. /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md /// /// ## What is `UnwindSafe`? /// -/// Now that we've got an idea of what panic safety is in Rust, it's also +/// Now that we've got an idea of what unwind safety is in Rust, it's also /// important to understand what this trait represents. As mentioned above, one -/// way to witness broken invariants is through the `recover` function in this +/// way to witness broken invariants is through the `catch_unwind` function in this /// module as it allows catching a panic and then re-using the environment of /// the closure. /// /// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow -/// witnessing a broken invariant through the use of `recover` (catching a +/// witnessing a broken invariant through the use of `catch_unwind` (catching a /// panic). This trait is a marker trait, so it is automatically implemented for -/// many types, and it is also structurally composed (e.g. a struct is recover -/// safe if all of its components are recover safe). +/// many types, and it is also structurally composed (e.g. a struct is unwind +/// safe if all of its components are unwind safe). /// /// Note, however, that this is not an unsafe trait, so there is not a succinct /// contract that this trait is providing. Instead it is intended as more of a -/// "speed bump" to alert users of `recover` that broken invariants may be +/// "speed bump" to alert users of `catch_unwind` that broken invariants may be /// witnessed and may need to be accounted for. /// /// ## Who implements `UnwindSafe`? /// /// Types such as `&mut T` and `&RefCell` are examples which are **not** -/// recover safe. The general idea is that any mutable state which can be shared -/// across `recover` is not recover safe by default. This is because it is very -/// easy to witness a broken invariant outside of `recover` as the data is +/// unwind safe. The general idea is that any mutable state which can be shared +/// across `catch_unwind` is not unwind safe by default. This is because it is very +/// easy to witness a broken invariant outside of `catch_unwind` as the data is /// simply accessed as usual. /// -/// Types like `&Mutex`, however, are recover safe because they implement +/// Types like `&Mutex`, however, are unwind safe because they implement /// poisoning by default. They still allow witnessing a broken invariant, but /// they already provide their own "speed bumps" to do so. /// /// ## When should `UnwindSafe` be used? /// /// Is not intended that most types or functions need to worry about this trait. -/// It is only used as a bound on the `recover` function and as mentioned above, +/// It is only used as a bound on the `catch_unwind` function and as mentioned above, /// the lack of `unsafe` means it is mostly an advisory. The `AssertUnwindSafe` /// wrapper struct in this module can be used to force this trait to be -/// implemented for any closed over variables passed to the `recover` function +/// implemented for any closed over variables passed to the `catch_unwind` function /// (more on this below). #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ - across a recover boundary"] + across an unwind boundary"] pub trait UnwindSafe {} /// Deprecated, renamed to UnwindSafe @@ -126,7 +126,7 @@ pub trait RecoverSafe {} impl RecoverSafe for T {} /// A marker trait representing types where a shared reference is considered -/// recover safe. +/// unwind safe. /// /// This trait is namely not implemented by `UnsafeCell`, the root of all /// interior mutability. @@ -136,23 +136,23 @@ impl RecoverSafe for T {} #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} contains interior mutability \ and a reference may not be safely transferrable \ - across a recover boundary"] + across a catch_unwind boundary"] pub trait RefUnwindSafe {} -/// A simple wrapper around a type to assert that it is panic safe. +/// A simple wrapper around a type to assert that it is unwind safe. /// -/// When using `recover` it may be the case that some of the closed over -/// variables are not panic safe. For example if `&mut T` is captured the -/// compiler will generate a warning indicating that it is not panic safe. It +/// When using `catch_unwind` it may be the case that some of the closed over +/// variables are not unwind safe. For example if `&mut T` is captured the +/// compiler will generate a warning indicating that it is not unwind safe. It /// may not be the case, however, that this is actually a problem due to the -/// specific usage of `recover` if panic safety is specifically taken into +/// specific usage of `catch_unwind` if unwind safety is specifically taken into /// account. This wrapper struct is useful for a quick and lightweight -/// annotation that a variable is indeed panic safe. +/// annotation that a variable is indeed unwind safe. /// /// # Examples /// /// One way to use `AssertUnwindSafe` is to assert that the entire closure -/// itself is recover safe, bypassing all checks for all variables: +/// itself is unwind safe, bypassing all checks for all variables: /// /// ``` /// use std::panic::{self, AssertUnwindSafe}; @@ -160,7 +160,7 @@ pub trait RefUnwindSafe {} /// let mut variable = 4; /// /// // This code will not compile because the closure captures `&mut variable` -/// // which is not considered panic safe by default. +/// // which is not considered unwind safe by default. /// /// // panic::catch_unwind(|| { /// // variable += 3; @@ -239,7 +239,7 @@ impl UnwindSafe for AssertUnwindSafe {} impl UnwindSafe for AssertRecoverSafe {} // not covered via the Shared impl above b/c the inner contents use -// Cell/AtomicUsize, but the usage here is recover safe so we can lift the +// Cell/AtomicUsize, but the usage here is unwind safe so we can lift the // impl up one level to Arc/Rc itself #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Rc {} @@ -352,9 +352,9 @@ impl R> FnOnce<()> for AssertRecoverSafe { /// that all captured variables are safe to cross this boundary. The purpose of /// this bound is to encode the concept of [exception safety][rfc] in the type /// system. Most usage of this function should not need to worry about this -/// bound as programs are naturally panic safe without `unsafe` code. If it +/// bound as programs are naturally unwind safe without `unsafe` code. If it /// becomes a problem the associated `AssertUnwindSafe` wrapper type in this -/// module can be used to quickly assert that the usage here is indeed exception +/// module can be used to quickly assert that the usage here is indeed unwind /// safe. /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md From 6e36ca1833b04e945e9b50adaa817222221c4631 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 23 May 2016 13:49:37 -0700 Subject: [PATCH 098/179] rustbuild: Add support for --enable-local-rust This commit adds support for the `--enable-local-rust` `./configure` switch which uses the locally installed `rustc` to bootstrap the compiler. --- src/bootstrap/build/config.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/build/config.rs b/src/bootstrap/build/config.rs index fb1ad12d914f..e155bf356a0d 100644 --- a/src/bootstrap/build/config.rs +++ b/src/bootstrap/build/config.rs @@ -65,8 +65,8 @@ pub struct Config { pub build: String, pub host: Vec, pub target: Vec, - pub rustc: Option, - pub cargo: Option, + pub rustc: Option, + pub cargo: Option, pub local_rebuild: bool, // libstd features @@ -208,8 +208,8 @@ impl Config { config.target.push(target.clone()); } } - config.rustc = build.rustc; - config.cargo = build.cargo; + config.rustc = build.rustc.map(PathBuf::from); + config.cargo = build.cargo.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); @@ -379,6 +379,10 @@ impl Config { .or_insert(Target::default()); target.ndk = Some(PathBuf::from(value)); } + "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { + self.rustc = Some(PathBuf::from(value).join("bin/rustc")); + self.cargo = Some(PathBuf::from(value).join("bin/cargo")); + } _ => {} } } From f66840ba404c0f39654bf08c7d22c1745326f509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ty=C3=A1s=20Mustoha?= Date: Fri, 20 May 2016 10:56:39 +0200 Subject: [PATCH 099/179] Fix asm-misplaced-option on ARM/AArch64 --- src/test/compile-fail/asm-misplaced-option.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/compile-fail/asm-misplaced-option.rs b/src/test/compile-fail/asm-misplaced-option.rs index 43a0ad6b5f6b..1020a5ba8a42 100644 --- a/src/test/compile-fail/asm-misplaced-option.rs +++ b/src/test/compile-fail/asm-misplaced-option.rs @@ -9,6 +9,8 @@ // except according to those terms. // ignore-android +// ignore-arm +// ignore-aarch64 #![feature(asm, rustc_attrs)] From efaa9421bd0b35426fff533707efdb7d366903db Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Wed, 18 May 2016 15:08:19 +0200 Subject: [PATCH 100/179] Make sure that macros that didn't pass LHS checking are not expanded. This avoids duplicate errors for things like invalid fragment specifiers, or parsing errors for ambiguous macros. Fixes #29231. --- src/libsyntax/ext/tt/macro_parser.rs | 11 +-- src/libsyntax/ext/tt/macro_rules.rs | 86 ++++++++++++------- .../compile-fail/invalid-macro-matcher.rs | 2 +- .../macro-invalid-fragment-spec.rs | 19 ++++ .../compile-fail/macro-missing-delimiters.rs | 17 ++++ 5 files changed, 93 insertions(+), 42 deletions(-) create mode 100644 src/test/compile-fail/macro-invalid-fragment-spec.rs create mode 100644 src/test/compile-fail/macro-missing-delimiters.rs diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 89ecf02ee4c9..ca5eb8f8003b 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -549,13 +549,8 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { token::NtPath(Box::new(panictry!(p.parse_path(PathStyle::Type)))) }, "meta" => token::NtMeta(panictry!(p.parse_meta_item())), - _ => { - p.span_fatal_help(sp, - &format!("invalid fragment specifier `{}`", name), - "valid fragment specifiers are `ident`, `block`, \ - `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ - and `item`").emit(); - panic!(FatalError); - } + // this is not supposed to happen, since it has been checked + // when compiling the macro. + _ => p.span_bug(sp, "invalid fragment specifier") } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 41d3991aee80..36d705f35969 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -299,7 +299,7 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt, }; for lhs in &lhses { - check_lhs_nt_follows(cx, lhs, def.span); + valid &= check_lhs_nt_follows(cx, lhs); } let rhses = match **argument_map.get(&rhs_nm.name).unwrap() { @@ -330,19 +330,19 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt, // why is this here? because of https://github.com/rust-lang/rust/issues/27774 fn ref_slice(s: &A) -> &[A] { use std::slice::from_raw_parts; unsafe { from_raw_parts(s, 1) } } -fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &TokenTree, sp: Span) { +fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. match lhs { - &TokenTree::Delimited(_, ref tts) => { - check_matcher(cx, &tts.tts); - }, - tt @ &TokenTree::Sequence(..) => { - check_matcher(cx, ref_slice(tt)); - }, - _ => cx.span_err(sp, "invalid macro matcher; matchers must be contained \ - in balanced delimiters or a repetition indicator") - }; + &TokenTree::Delimited(_, ref tts) => check_matcher(cx, &tts.tts), + tt @ &TokenTree::Sequence(..) => check_matcher(cx, ref_slice(tt)), + _ => { + cx.span_err(lhs.get_span(), + "invalid macro matcher; matchers must be contained \ + in balanced delimiters or a repetition indicator"); + false + } + } // we don't abort on errors on rejection, the driver will do that for us // after parsing/expansion. we can report every error in every macro this way. } @@ -364,20 +364,25 @@ struct OnFail { action: OnFailAction, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] enum OnFailAction { Warn, Error, DoNothing } impl OnFail { fn warn() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::Warn } } fn error() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::Error } } fn do_nothing() -> OnFail { OnFail { saw_failure: false, action: OnFailAction::DoNothing } } - fn react(&mut self, cx: &mut ExtCtxt, sp: Span, msg: &str) { + fn react(&mut self, cx: &mut ExtCtxt, sp: Span, msg: &str, help: Option<&str>) { match self.action { OnFailAction::DoNothing => {} - OnFailAction::Error => cx.span_err(sp, msg), + OnFailAction::Error => { + let mut err = cx.struct_span_err(sp, msg); + if let Some(msg) = help { err.span_help(sp, msg); } + err.emit(); + } OnFailAction::Warn => { - cx.struct_span_warn(sp, msg) - .span_note(sp, "The above warning will be a hard error in the next release.") + let mut warn = cx.struct_span_warn(sp, msg); + if let Some(msg) = help { warn.span_help(sp, msg); } + warn.span_note(sp, "The above warning will be a hard error in the next release.") .emit(); } }; @@ -385,7 +390,7 @@ impl OnFail { } } -fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) { +fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) -> bool { // Issue 30450: when we are through a warning cycle, we can just // error on all failure conditions (and remove check_matcher_old). @@ -400,6 +405,9 @@ fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) { OnFail::warn() }; check_matcher_new(cx, matcher, &mut on_fail); + // matcher is valid if the new pass didn't see any error, + // or if errors were considered warnings + on_fail.action != OnFailAction::Error || !on_fail.saw_failure } // returns the last token that was checked, for TokenTree::Sequence. @@ -435,11 +443,11 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai // sequence, which may itself be a sequence, // and so on). on_fail.react(cx, sp, - &format!("`${0}:{1}` is followed by a \ - sequence repetition, which is not \ - allowed for `{1}` fragments", - name, frag_spec) - ); + &format!("`${0}:{1}` is followed by a \ + sequence repetition, which is not \ + allowed for `{1}` fragments", + name, frag_spec), + None); Eof }, // die next iteration @@ -456,8 +464,10 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai // If T' is in the set FOLLOW(NT), continue. Else, reject. match (&next_token, is_in_follow(cx, &next_token, &frag_spec.name.as_str())) { - (_, Err(msg)) => { - on_fail.react(cx, sp, &msg); + (_, Err((msg, _))) => { + // no need for help message, those messages + // are never emitted anyway... + on_fail.react(cx, sp, &msg, None); continue } (&Eof, _) => return Some((sp, tok.clone())), @@ -466,7 +476,7 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai on_fail.react(cx, sp, &format!("`${0}:{1}` is followed by `{2}`, which \ is not allowed for `{1}` fragments", name, frag_spec, - token_to_string(next))); + token_to_string(next)), None); continue }, } @@ -494,7 +504,8 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai delim.close_token(), Some(_) => { on_fail.react(cx, sp, "sequence repetition followed by \ - another sequence repetition, which is not allowed"); + another sequence repetition, which is not allowed", + None); Eof }, None => Eof @@ -514,7 +525,7 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai Some(&&TokenTree::Delimited(_, ref delim)) => delim.close_token(), Some(_) => { on_fail.react(cx, sp, "sequence repetition followed by another \ - sequence repetition, which is not allowed"); + sequence repetition, which is not allowed", None); Eof }, None => Eof @@ -810,7 +821,11 @@ fn check_matcher_core(cx: &mut ExtCtxt, TokenTree::Token(sp, ref tok) => { let can_be_followed_by_any; if let Err(bad_frag) = has_legal_fragment_specifier(tok) { - on_fail.react(cx, sp, &format!("invalid fragment specifier `{}`", bad_frag)); + on_fail.react(cx, sp, + &format!("invalid fragment specifier `{}`", bad_frag), + Some("valid fragment specifiers are `ident`, `block`, \ + `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ + and `item`")); // (This eliminates false positives and duplicates // from error messages.) can_be_followed_by_any = true; @@ -884,8 +899,8 @@ fn check_matcher_core(cx: &mut ExtCtxt, if let MatchNt(ref name, ref frag_spec) = *t { for &(sp, ref next_token) in &suffix_first.tokens { match is_in_follow(cx, next_token, &frag_spec.name.as_str()) { - Err(msg) => { - on_fail.react(cx, sp, &msg); + Err((msg, help)) => { + on_fail.react(cx, sp, &msg, Some(help)); // don't bother reporting every source of // conflict for a particular element of `last`. continue 'each_last; @@ -907,7 +922,9 @@ fn check_matcher_core(cx: &mut ExtCtxt, name=name, frag=frag_spec, next=token_to_string(next_token), - may_be=may_be)); + may_be=may_be), + None + ); } } } @@ -978,7 +995,7 @@ fn can_be_followed_by_any(frag: &str) -> bool { /// break macros that were relying on that binary operator as a /// separator. // when changing this do not forget to update doc/book/macros.md! -fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { +fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { if let &CloseDelim(_) = tok { // closing a token tree can never be matched by any fragment; // iow, we always require that `(` and `)` match, etc. @@ -1027,7 +1044,10 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { // harmless Ok(true) }, - _ => Err(format!("invalid fragment specifier `{}`", frag)) + _ => Err((format!("invalid fragment specifier `{}`", frag), + "valid fragment specifiers are `ident`, `block`, \ + `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ + and `item`")) } } } diff --git a/src/test/compile-fail/invalid-macro-matcher.rs b/src/test/compile-fail/invalid-macro-matcher.rs index 03bcaab4a9db..a0ac5d4c7204 100644 --- a/src/test/compile-fail/invalid-macro-matcher.rs +++ b/src/test/compile-fail/invalid-macro-matcher.rs @@ -9,7 +9,7 @@ // except according to those terms. macro_rules! invalid { - _ => (); //~^ ERROR invalid macro matcher + _ => (); //~ ERROR invalid macro matcher } fn main() { diff --git a/src/test/compile-fail/macro-invalid-fragment-spec.rs b/src/test/compile-fail/macro-invalid-fragment-spec.rs new file mode 100644 index 000000000000..ca6cd664e738 --- /dev/null +++ b/src/test/compile-fail/macro-invalid-fragment-spec.rs @@ -0,0 +1,19 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! foo( + ($x:foo) => () + //~^ ERROR invalid fragment specifier + //~| HELP valid fragment specifiers are +); + +fn main() { + foo!(foo); +} diff --git a/src/test/compile-fail/macro-missing-delimiters.rs b/src/test/compile-fail/macro-missing-delimiters.rs new file mode 100644 index 000000000000..eed2a207e89e --- /dev/null +++ b/src/test/compile-fail/macro-missing-delimiters.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! baz( + baz => () //~ ERROR invalid macro matcher; +); + +fn main() { + baz!(baz); +} From f0e7f839691a8dd746a682ff0d69ab0baece65c2 Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Thu, 19 May 2016 00:38:08 +0200 Subject: [PATCH 101/179] Avoid iterating two times over the list of LHSes. --- src/libsyntax/ext/tt/macro_rules.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 36d705f35969..3522c8863cf5 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -291,17 +291,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt, let lhses = match **argument_map.get(&lhs_nm.name).unwrap() { MatchedSeq(ref s, _) => { s.iter().map(|m| match **m { - MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(), + MatchedNonterminal(NtTT(ref tt)) => { + valid &= check_lhs_nt_follows(cx, tt); + (**tt).clone() + } _ => cx.span_bug(def.span, "wrong-structured lhs") }).collect() } _ => cx.span_bug(def.span, "wrong-structured lhs") }; - for lhs in &lhses { - valid &= check_lhs_nt_follows(cx, lhs); - } - let rhses = match **argument_map.get(&rhs_nm.name).unwrap() { MatchedSeq(ref s, _) => { s.iter().map(|m| match **m { From 860afcf5a5af8cb0e3bad7abff3462a008542103 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 12:35:35 +0200 Subject: [PATCH 102/179] bug fix to `borrowck::indexed_set`: wanted bit-count not byte-count. --- src/librustc_borrowck/indexed_set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs index c37f8e09e0ac..bf5eb10b8ed5 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_borrowck/indexed_set.rs @@ -57,7 +57,7 @@ impl fmt::Debug for IdxSet { impl OwnIdxSet { fn new(init: Word, universe_size: usize) -> Self { - let bits_per_word = mem::size_of::(); + let bits_per_word = mem::size_of::() * 8; let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word; OwnIdxSet { _pd: Default::default(), From 2d155664ebce1955533a45eed7b90a7d31c529ba Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 12:37:39 +0200 Subject: [PATCH 103/179] Fix comment within sanity_check. --- .../borrowck/mir/dataflow/sanity_check.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 6cf20def0e0c..3151195a5ad0 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -80,9 +80,10 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let move_data = flow_ctxt.move_data(); // Emulate effect of all statements in the block up to (but - // not including) the assignment to `peek_arg_lval`. Do *not* - // include terminator (since we are peeking the state of the - // argument at time immediate preceding Call to `rustc_peek`). + // not including) the borrow within `peek_arg_lval`. Do *not* + // include call to `peek_arg_lval` itself (since we are + // peeking the state of the argument at time immediate + // preceding Call to `rustc_peek`). let mut sets = super::BlockSets { on_entry: &mut entry, gen_set: &mut gen, From b3f3a89a6ad09f75b6db16289515d4ae6fbb9447 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 12:56:02 +0200 Subject: [PATCH 104/179] `mir::dataflow::sanity_check`: extract an `fn each_block` to simplify presentation. As a drive-by: unified pair of match arms that flowed to `bug!`, and replaced `bug!` invocation with a diagnostic `span_err` invocation. --- .../borrowck/mir/dataflow/sanity_check.rs | 162 ++++++++++-------- 1 file changed, 86 insertions(+), 76 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 3151195a5ad0..932975b88084 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -51,92 +51,102 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let blocks = mir.all_basic_blocks(); 'next_block: for bb in blocks { - let bb_data = mir.basic_block_data(bb); - let &repr::BasicBlockData { ref statements, - ref terminator, - is_cleanup: _ } = bb_data; - - let (args, span) = match is_rustc_peek(tcx, terminator) { - Some(args_and_span) => args_and_span, - None => continue, - }; - assert!(args.len() == 1); - let peek_arg_lval = match args[0] { - repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => { - lval - } - repr::Operand::Consume(_) => { - bug!("dataflow::sanity_check cannot feed a non-temp to rustc_peek."); - } - repr::Operand::Constant(_) => { - bug!("dataflow::sanity_check cannot feed a constant to rustc_peek."); - } - }; + each_block(tcx, mir, flow_ctxt, results, bb); + } +} - let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned(); - let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned(); - let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned(); +fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + flow_ctxt: &O::Ctxt, + results: &DataflowResults, + bb: repr::BasicBlock) where + O: BitDenotation, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx> +{ + let bb_data = mir.basic_block_data(bb); + let &repr::BasicBlockData { ref statements, + ref terminator, + is_cleanup: _ } = bb_data; + + let (args, span) = match is_rustc_peek(tcx, terminator) { + Some(args_and_span) => args_and_span, + None => return, + }; + assert!(args.len() == 1); + let peek_arg_lval = match args[0] { + repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => { + lval + } + repr::Operand::Consume(_) | + repr::Operand::Constant(_) => { + tcx.sess.diagnostic().span_err( + span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek."); + return; + } + }; - let move_data = flow_ctxt.move_data(); + let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned(); + let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned(); + let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned(); - // Emulate effect of all statements in the block up to (but - // not including) the borrow within `peek_arg_lval`. Do *not* - // include call to `peek_arg_lval` itself (since we are - // peeking the state of the argument at time immediate - // preceding Call to `rustc_peek`). + let move_data = flow_ctxt.move_data(); - let mut sets = super::BlockSets { on_entry: &mut entry, - gen_set: &mut gen, - kill_set: &mut kill }; + // Emulate effect of all statements in the block up to (but not + // including) the borrow within `peek_arg_lval`. Do *not* include + // call to `peek_arg_lval` itself (since we are peeking the state + // of the argument at time immediate preceding Call to + // `rustc_peek`). - for (j, stmt) in statements.iter().enumerate() { - debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); - let (lvalue, rvalue) = match stmt.kind { - repr::StatementKind::Assign(ref lvalue, ref rvalue) => { - (lvalue, rvalue) - } - }; - - if lvalue == peek_arg_lval { - if let repr::Rvalue::Ref(_, - repr::BorrowKind::Shared, - ref peeking_at_lval) = *rvalue { - // Okay, our search is over. - let peek_mpi = move_data.rev_lookup.find(peeking_at_lval); - let bit_state = sets.on_entry.contains(&peek_mpi); - debug!("rustc_peek({:?} = &{:?}) bit_state: {}", - lvalue, peeking_at_lval, bit_state); - if !bit_state { - tcx.sess.span_err(span, &format!("rustc_peek: bit not set")); - } - continue 'next_block; - } else { - // Our search should have been over, but the input - // does not match expectations of `rustc_peek` for - // this sanity_check. - tcx.sess.span_err(span, &format!("rustc_peek: argument expression \ - must be immediate borrow of form `&expr`")); - } - } + let mut sets = super::BlockSets { on_entry: &mut entry, + gen_set: &mut gen, + kill_set: &mut kill }; - let lhs_mpi = move_data.rev_lookup.find(lvalue); + for (j, stmt) in statements.iter().enumerate() { + debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); + let (lvalue, rvalue) = match stmt.kind { + repr::StatementKind::Assign(ref lvalue, ref rvalue) => { + (lvalue, rvalue) + } + }; - debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}", - lvalue, lhs_mpi, stmt); - // reset GEN and KILL sets before emulating their effect. - for e in sets.gen_set.words_mut() { *e = 0; } - for e in sets.kill_set.words_mut() { *e = 0; } - results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j); - sets.on_entry.union(sets.gen_set); - sets.on_entry.subtract(sets.kill_set); + if lvalue == peek_arg_lval { + if let repr::Rvalue::Ref(_, + repr::BorrowKind::Shared, + ref peeking_at_lval) = *rvalue { + // Okay, our search is over. + let peek_mpi = move_data.rev_lookup.find(peeking_at_lval); + let bit_state = sets.on_entry.contains(&peek_mpi); + debug!("rustc_peek({:?} = &{:?}) bit_state: {}", + lvalue, peeking_at_lval, bit_state); + if !bit_state { + tcx.sess.span_err(span, &format!("rustc_peek: bit not set")); + } + return; + } else { + // Our search should have been over, but the input + // does not match expectations of `rustc_peek` for + // this sanity_check. + let msg = &format!("rustc_peek: argument expression \ + must be immediate borrow of form `&expr`"); + tcx.sess.span_err(span, msg); + } } - - tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ - anticipated pattern; note that \ - rustc_peek expects input of \ - form `&expr`")); + + let lhs_mpi = move_data.rev_lookup.find(lvalue); + + debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}", + lvalue, lhs_mpi, stmt); + // reset GEN and KILL sets before emulating their effect. + for e in sets.gen_set.words_mut() { *e = 0; } + for e in sets.kill_set.words_mut() { *e = 0; } + results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j); + sets.on_entry.union(sets.gen_set); + sets.on_entry.subtract(sets.kill_set); } + tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \ + anticipated pattern; note that \ + rustc_peek expects input of \ + form `&expr`")); } fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, From 0a1b35a7cf035981a696d10ee16f53bace2cbfef Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 13:26:54 +0200 Subject: [PATCH 105/179] Moved the four impls of `BitDenotation` to their own module, `mod impls`. --- .../borrowck/mir/dataflow/impls.rs | 584 ++++++++++++++++++ .../borrowck/mir/dataflow/mod.rs | 573 +---------------- 2 files changed, 588 insertions(+), 569 deletions(-) create mode 100644 src/librustc_borrowck/borrowck/mir/dataflow/impls.rs diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs new file mode 100644 index 000000000000..c9a23e3f288b --- /dev/null +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -0,0 +1,584 @@ +// Copyright 2012-2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use rustc::mir::repr::{self, Mir}; + +use super::super::gather_moves::{Location}; +use super::super::gather_moves::{MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex}; +use super::super::DropFlagState; +use super::super::drop_flag_effects_for_function_entry; +use super::super::drop_flag_effects_for_location; +use super::super::on_all_children_bits; + +use super::{BitDenotation, BlockSets, DataflowOperator}; + +use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. +use bitslice::{BitwiseOperator}; +use indexed_set::{Idx, IdxSet}; + +use std::marker::PhantomData; + +// Dataflow analyses are built upon some interpretation of the +// bitvectors attached to each basic block, represented via a +// zero-sized structure. +// +// Note on PhantomData: Each interpretation will need to instantiate +// the `Bit` and `Ctxt` associated types, and in this case, those +// associated types need an associated lifetime `'tcx`. The +// interpretive structures are zero-sized, so they all need to carry a +// `PhantomData` representing how the structures relate to the `'tcx` +// lifetime. +// +// But, since all of the uses of `'tcx` are solely via instances of +// `Ctxt` that are passed into the `BitDenotation` methods, we can +// consistently use a `PhantomData` that is just a function over a +// `&Ctxt` (== `&MoveData<'tcx>). + +/// `MaybeInitializedLvals` tracks all l-values that might be +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-init: +/// // {} +/// let a = S; let b = S; let c; let d; // {a, b} +/// +/// if pred { +/// drop(a); // { b} +/// b = S; // { b} +/// +/// } else { +/// drop(b); // {a} +/// d = S; // {a, d} +/// +/// } // {a, b, d} +/// +/// c = S; // {a, b, c, d} +/// } +/// ``` +/// +/// To determine whether an l-value *must* be initialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeUninitializedLvals` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeUninitializedLvals` yields the set of +/// l-values that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct MaybeInitializedLvals<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + +/// `MaybeUninitializedLvals` tracks all l-values that might be +/// uninitialized upon reaching a particular point in the control flow +/// for a function. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // maybe-uninit: +/// // {a, b, c, d} +/// let a = S; let b = S; let c; let d; // { c, d} +/// +/// if pred { +/// drop(a); // {a, c, d} +/// b = S; // {a, c, d} +/// +/// } else { +/// drop(b); // { b, c, d} +/// d = S; // { b, c } +/// +/// } // {a, b, c, d} +/// +/// c = S; // {a, b, d} +/// } +/// ``` +/// +/// To determine whether an l-value *must* be uninitialized at a +/// particular control-flow point, one can take the set-difference +/// between this data and the data from `MaybeInitializedLvals` at the +/// corresponding control-flow point. +/// +/// Similarly, at a given `drop` statement, the set-intersection +/// between this data and `MaybeInitializedLvals` yields the set of +/// l-values that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + +/// `DefinitelyInitializedLvals` tracks all l-values that are definitely +/// initialized upon reaching a particular point in the control flow +/// for a function. +/// +/// FIXME: Note that once flow-analysis is complete, this should be +/// the set-complement of MaybeUninitializedLvals; thus we can get rid +/// of one or the other of these two. I'm inclined to get rid of +/// MaybeUninitializedLvals, simply because the sets will tend to be +/// smaller in this analysis and thus easier for humans to process +/// when debugging. +/// +/// For example, in code like the following, we have corresponding +/// dataflow information shown in the right-hand comments. +/// +/// ```rust +/// struct S; +/// fn foo(pred: bool) { // definite-init: +/// // { } +/// let a = S; let b = S; let c; let d; // {a, b } +/// +/// if pred { +/// drop(a); // { b, } +/// b = S; // { b, } +/// +/// } else { +/// drop(b); // {a, } +/// d = S; // {a, d} +/// +/// } // { } +/// +/// c = S; // { c } +/// } +/// ``` +/// +/// To determine whether an l-value *may* be uninitialized at a +/// particular control-flow point, one can take the set-complement +/// of this data. +/// +/// Similarly, at a given `drop` statement, the set-difference between +/// this data and `MaybeInitializedLvals` yields the set of l-values +/// that would require a dynamic drop-flag at that statement. +#[derive(Debug, Default)] +pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + +/// `MovingOutStatements` tracks the statements that perform moves out +/// of particular l-values. More precisely, it tracks whether the +/// *effect* of such moves (namely, the uninitialization of the +/// l-value in question) can reach some point in the control-flow of +/// the function, or if that effect is "killed" by some intervening +/// operation reinitializing that l-value. +/// +/// The resulting dataflow is a more enriched version of +/// `MaybeUninitializedLvals`. Both structures on their own only tell +/// you if an l-value *might* be uninitialized at a given point in the +/// control flow. But `MovingOutStatements` also includes the added +/// data of *which* particular statement causing the deinitialization +/// that the borrow checker's error meessage may need to report. +#[derive(Debug, Default)] +pub struct MovingOutStatements<'a, 'tcx: 'a> { + // See "Note on PhantomData" above. + phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> +} + +impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + state: DropFlagState) + { + match state { + DropFlagState::Absent => sets.kill(&path), + DropFlagState::Present => sets.gen(&path), + } + } +} + +impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + state: DropFlagState) + { + match state { + DropFlagState::Absent => sets.gen(&path), + DropFlagState::Present => sets.kill(&path), + } + } +} + +impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { + fn update_bits(sets: &mut BlockSets, path: MovePathIndex, + state: DropFlagState) + { + match state { + DropFlagState::Absent => sets.kill(&path), + DropFlagState::Present => sets.gen(&path), + } + } +} + +impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { + type Idx = MovePathIndex; + type Bit = MovePath<'tcx>; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "maybe_init" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.move_paths.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.move_paths[MovePathIndex::new(idx)] + } + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) + { + drop_flag_effects_for_function_entry( + ctxt.0, ctxt.1, &ctxt.2, + |path, s| { + assert!(s == DropFlagState::Present); + sets.on_entry.add(&path); + }); + } + + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) + { + drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: idx }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: statements_len }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut IdxSet, + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + // when a call returns successfully, that means we need to set + // the bits for that dest_lval to 1 (initialized). + let move_data = &ctxt.2; + let move_path_index = move_data.rev_lookup.find(dest_lval); + on_all_children_bits(ctxt.0, ctxt.1, &ctxt.2, + move_path_index, + |mpi| { in_out.add(&mpi); }); + } +} + +impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { + type Idx = MovePathIndex; + type Bit = MovePath<'tcx>; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "maybe_uninit" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.move_paths.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.move_paths[MovePathIndex::new(idx)] + } + + // sets on_entry bits for Arg lvalues + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { + // set all bits to 1 (uninit) before gathering counterevidence + for e in sets.on_entry.words_mut() { *e = !0; } + + drop_flag_effects_for_function_entry( + ctxt.0, ctxt.1, &ctxt.2, + |path, s| { + assert!(s == DropFlagState::Present); + sets.on_entry.remove(&path); + }); + } + + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) + { + drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: idx }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: statements_len }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut IdxSet, + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + // when a call returns successfully, that means we need to set + // the bits for that dest_lval to 1 (initialized). + let move_path_index = ctxt.2.rev_lookup.find(dest_lval); + on_all_children_bits(ctxt.0, ctxt.1, &ctxt.2, + move_path_index, + |mpi| { in_out.remove(&mpi); }); + } +} + +impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { + type Idx = MovePathIndex; + type Bit = MovePath<'tcx>; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "definite_init" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.move_paths.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.move_paths[MovePathIndex::new(idx)] + } + + // sets on_entry bits for Arg lvalues + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { + for e in sets.on_entry.words_mut() { *e = 0; } + + drop_flag_effects_for_function_entry( + ctxt.0, ctxt.1, &ctxt.2, + |path, s| { + assert!(s == DropFlagState::Present); + sets.on_entry.add(&path); + }); + } + + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) + { + drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: idx }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + drop_flag_effects_for_location( + ctxt.0, ctxt.1, &ctxt.2, + Location { block: bb, index: statements_len }, + |path, s| Self::update_bits(sets, path, s) + ) + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut IdxSet, + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + // when a call returns successfully, that means we need to set + // the bits for that dest_lval to 1 (initialized). + let move_path_index = ctxt.2.rev_lookup.find(dest_lval); + on_all_children_bits(ctxt.0, ctxt.1, &ctxt.2, + move_path_index, + |mpi| { in_out.add(&mpi); }); + } +} + +impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { + type Idx = MoveOutIndex; + type Bit = MoveOut; + type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + fn name() -> &'static str { "moving_out" } + fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { + ctxt.2.moves.len() + } + fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { + &ctxt.2.moves[idx] + } + fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { + // no move-statements have been executed prior to function + // execution, so this method has no effect on `_sets`. + } + fn statement_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + idx: usize) { + let &(tcx, mir, ref move_data) = ctxt; + let stmt = &mir.basic_block_data(bb).statements[idx]; + let loc_map = &move_data.loc_map; + let path_map = &move_data.path_map; + let rev_lookup = &move_data.rev_lookup; + + let loc = Location { block: bb, index: idx }; + debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}", + stmt, loc, &loc_map[loc]); + for move_index in &loc_map[loc] { + // Every path deinitialized by a *particular move* + // has corresponding bit, "gen'ed" (i.e. set) + // here, in dataflow vector + zero_to_one(sets.gen_set.words_mut(), *move_index); + } + let bits_per_block = self.bits_per_block(ctxt); + match stmt.kind { + repr::StatementKind::Assign(ref lvalue, _) => { + // assigning into this `lvalue` kills all + // MoveOuts from it, and *also* all MoveOuts + // for children and associated fragment sets. + let move_path_index = rev_lookup.find(lvalue); + on_all_children_bits(tcx, + mir, + move_data, + move_path_index, + |mpi| for moi in &path_map[mpi] { + assert!(moi.idx() < bits_per_block); + sets.kill_set.add(&moi); + }); + } + } + } + + fn terminator_effect(&self, + ctxt: &Self::Ctxt, + sets: &mut BlockSets, + bb: repr::BasicBlock, + statements_len: usize) + { + let &(_tcx, mir, ref move_data) = ctxt; + let term = mir.basic_block_data(bb).terminator.as_ref().unwrap(); + let loc_map = &move_data.loc_map; + let loc = Location { block: bb, index: statements_len }; + debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}", + term, loc, &loc_map[loc]); + let bits_per_block = self.bits_per_block(ctxt); + for move_index in &loc_map[loc] { + assert!(move_index.idx() < bits_per_block); + zero_to_one(sets.gen_set.words_mut(), *move_index); + } + } + + fn propagate_call_return(&self, + ctxt: &Self::Ctxt, + in_out: &mut IdxSet, + _call_bb: repr::BasicBlock, + _dest_bb: repr::BasicBlock, + dest_lval: &repr::Lvalue) { + let move_data = &ctxt.2; + let move_path_index = move_data.rev_lookup.find(dest_lval); + let bits_per_block = self.bits_per_block(ctxt); + + let path_map = &move_data.path_map; + on_all_children_bits(ctxt.0, + ctxt.1, + move_data, + move_path_index, + |mpi| for moi in &path_map[mpi] { + assert!(moi.idx() < bits_per_block); + in_out.remove(&moi); + }); + } +} + +fn zero_to_one(bitvec: &mut [usize], move_index: MoveOutIndex) { + let retval = bitvec.set_bit(move_index.idx()); + assert!(retval); +} + +impl<'a, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // moves from both preds are in scope + } +} + +impl<'a, 'tcx> BitwiseOperator for MaybeInitializedLvals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // "maybe" means we union effects of both preds + } +} + +impl<'a, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // "maybe" means we union effects of both preds + } +} + +impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 & pred2 // "definitely" means we intersect effects of both preds + } +} + +// The way that dataflow fixed point iteration works, you want to +// start at bottom and work your way to a fixed point. Control-flow +// merges will apply the `join` operator to each block entry's current +// state (which starts at that bottom value). +// +// This means, for propagation across the graph, that you either want +// to start at all-zeroes and then use Union as your merge when +// propagating, or you start at all-ones and then use Intersect as +// your merge when propagating. + +impl<'a, 'tcx> DataflowOperator for MovingOutStatements<'a, 'tcx> { + #[inline] + fn bottom_value() -> bool { + false // bottom = no loans in scope by default + } +} + +impl<'a, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'tcx> { + #[inline] + fn bottom_value() -> bool { + false // bottom = uninitialized + } +} + +impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> { + #[inline] + fn bottom_value() -> bool { + false // bottom = initialized (start_block_effect counters this at outset) + } +} + +impl<'a, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'tcx> { + #[inline] + fn bottom_value() -> bool { + true // bottom = initialized (start_block_effect counters this at outset) + } +} diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index e1459ad2abea..97e29fe064fe 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -13,24 +13,23 @@ use rustc::mir::repr::{self, Mir}; use std::fmt::Debug; use std::io; -use std::marker::PhantomData; use std::mem; use std::path::PathBuf; use std::usize; use super::MirBorrowckCtxtPreDataflow; -use super::gather_moves::{Location, MoveData, MovePathIndex, MoveOutIndex}; -use super::gather_moves::{MoveOut, MovePath}; -use super::DropFlagState; +use super::gather_moves::{MoveData}; -use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. use bitslice::{bitwise, BitwiseOperator}; use indexed_set::{Idx, IdxSet, OwnIdxSet}; pub use self::sanity_check::sanity_check_via_rustc_peek; +pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals}; +pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements}; mod graphviz; mod sanity_check; +mod impls; pub trait Dataflow { fn dataflow(&mut self); @@ -550,567 +549,3 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> } } } - -// Dataflow analyses are built upon some interpretation of the -// bitvectors attached to each basic block, represented via a -// zero-sized structure. -// -// Note on PhantomData: Each interpretation will need to instantiate -// the `Bit` and `Ctxt` associated types, and in this case, those -// associated types need an associated lifetime `'tcx`. The -// interpretive structures are zero-sized, so they all need to carry a -// `PhantomData` representing how the structures relate to the `'tcx` -// lifetime. -// -// But, since all of the uses of `'tcx` are solely via instances of -// `Ctxt` that are passed into the `BitDenotation` methods, we can -// consistently use a `PhantomData` that is just a function over a -// `&Ctxt` (== `&MoveData<'tcx>). - -/// `MaybeInitializedLvals` tracks all l-values that might be -/// initialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-init: -/// // {} -/// let a = S; let b = S; let c; let d; // {a, b} -/// -/// if pred { -/// drop(a); // { b} -/// b = S; // { b} -/// -/// } else { -/// drop(b); // {a} -/// d = S; // {a, d} -/// -/// } // {a, b, d} -/// -/// c = S; // {a, b, c, d} -/// } -/// ``` -/// -/// To determine whether an l-value *must* be initialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeUninitializedLvals` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeUninitializedLvals` yields the set of -/// l-values that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] -pub struct MaybeInitializedLvals<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> -} - -/// `MaybeUninitializedLvals` tracks all l-values that might be -/// uninitialized upon reaching a particular point in the control flow -/// for a function. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // maybe-uninit: -/// // {a, b, c, d} -/// let a = S; let b = S; let c; let d; // { c, d} -/// -/// if pred { -/// drop(a); // {a, c, d} -/// b = S; // {a, c, d} -/// -/// } else { -/// drop(b); // { b, c, d} -/// d = S; // { b, c } -/// -/// } // {a, b, c, d} -/// -/// c = S; // {a, b, d} -/// } -/// ``` -/// -/// To determine whether an l-value *must* be uninitialized at a -/// particular control-flow point, one can take the set-difference -/// between this data and the data from `MaybeInitializedLvals` at the -/// corresponding control-flow point. -/// -/// Similarly, at a given `drop` statement, the set-intersection -/// between this data and `MaybeInitializedLvals` yields the set of -/// l-values that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] -pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> -} - -/// `DefinitelyInitializedLvals` tracks all l-values that are definitely -/// initialized upon reaching a particular point in the control flow -/// for a function. -/// -/// FIXME: Note that once flow-analysis is complete, this should be -/// the set-complement of MaybeUninitializedLvals; thus we can get rid -/// of one or the other of these two. I'm inclined to get rid of -/// MaybeUninitializedLvals, simply because the sets will tend to be -/// smaller in this analysis and thus easier for humans to process -/// when debugging. -/// -/// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. -/// -/// ```rust -/// struct S; -/// fn foo(pred: bool) { // definite-init: -/// // { } -/// let a = S; let b = S; let c; let d; // {a, b } -/// -/// if pred { -/// drop(a); // { b, } -/// b = S; // { b, } -/// -/// } else { -/// drop(b); // {a, } -/// d = S; // {a, d} -/// -/// } // { } -/// -/// c = S; // { c } -/// } -/// ``` -/// -/// To determine whether an l-value *may* be uninitialized at a -/// particular control-flow point, one can take the set-complement -/// of this data. -/// -/// Similarly, at a given `drop` statement, the set-difference between -/// this data and `MaybeInitializedLvals` yields the set of l-values -/// that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] -pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> -} - -/// `MovingOutStatements` tracks the statements that perform moves out -/// of particular l-values. More precisely, it tracks whether the -/// *effect* of such moves (namely, the uninitialization of the -/// l-value in question) can reach some point in the control-flow of -/// the function, or if that effect is "killed" by some intervening -/// operation reinitializing that l-value. -/// -/// The resulting dataflow is a more enriched version of -/// `MaybeUninitializedLvals`. Both structures on their own only tell -/// you if an l-value *might* be uninitialized at a given point in the -/// control flow. But `MovingOutStatements` also includes the added -/// data of *which* particular statement causing the deinitialization -/// that the borrow checker's error meessage may need to report. -#[derive(Debug, Default)] -pub struct MovingOutStatements<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> -} - -impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { - type Idx = MoveOutIndex; - type Bit = MoveOut; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); - fn name() -> &'static str { "moving_out" } - fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.moves.len() - } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.moves[idx] - } - fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { - // no move-statements have been executed prior to function - // execution, so this method has no effect on `_sets`. - } - fn statement_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - idx: usize) { - let &(tcx, mir, ref move_data) = ctxt; - let stmt = &mir.basic_block_data(bb).statements[idx]; - let loc_map = &move_data.loc_map; - let path_map = &move_data.path_map; - let rev_lookup = &move_data.rev_lookup; - - let loc = Location { block: bb, index: idx }; - debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}", - stmt, loc, &loc_map[loc]); - for move_index in &loc_map[loc] { - // Every path deinitialized by a *particular move* - // has corresponding bit, "gen'ed" (i.e. set) - // here, in dataflow vector - zero_to_one(sets.gen_set.words_mut(), *move_index); - } - let bits_per_block = self.bits_per_block(ctxt); - match stmt.kind { - repr::StatementKind::Assign(ref lvalue, _) => { - // assigning into this `lvalue` kills all - // MoveOuts from it, and *also* all MoveOuts - // for children and associated fragment sets. - let move_path_index = rev_lookup.find(lvalue); - super::on_all_children_bits(tcx, - mir, - move_data, - move_path_index, - |mpi| for moi in &path_map[mpi] { - assert!(moi.idx() < bits_per_block); - sets.kill_set.add(&moi); - }); - } - } - } - - fn terminator_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - statements_len: usize) - { - let &(_tcx, mir, ref move_data) = ctxt; - let term = mir.basic_block_data(bb).terminator.as_ref().unwrap(); - let loc_map = &move_data.loc_map; - let loc = Location { block: bb, index: statements_len }; - debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}", - term, loc, &loc_map[loc]); - let bits_per_block = self.bits_per_block(ctxt); - for move_index in &loc_map[loc] { - assert!(move_index.idx() < bits_per_block); - zero_to_one(sets.gen_set.words_mut(), *move_index); - } - } - - fn propagate_call_return(&self, - ctxt: &Self::Ctxt, - in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { - let move_data = &ctxt.2; - let move_path_index = move_data.rev_lookup.find(dest_lval); - let bits_per_block = self.bits_per_block(ctxt); - - let path_map = &move_data.path_map; - super::on_all_children_bits(ctxt.0, - ctxt.1, - move_data, - move_path_index, - |mpi| for moi in &path_map[mpi] { - assert!(moi.idx() < bits_per_block); - in_out.remove(&moi); - }); - } -} - -impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { - fn update_bits(sets: &mut BlockSets, path: MovePathIndex, - state: super::DropFlagState) - { - match state { - DropFlagState::Absent => sets.kill(&path), - DropFlagState::Present => sets.gen(&path), - } - } -} - -impl<'a, 'tcx> MaybeUninitializedLvals<'a, 'tcx> { - fn update_bits(sets: &mut BlockSets, path: MovePathIndex, - state: super::DropFlagState) - { - match state { - DropFlagState::Absent => sets.gen(&path), - DropFlagState::Present => sets.kill(&path), - } - } -} - -impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { - fn update_bits(sets: &mut BlockSets, path: MovePathIndex, - state: super::DropFlagState) - { - match state { - DropFlagState::Absent => sets.kill(&path), - DropFlagState::Present => sets.gen(&path), - } - } -} - -impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { - type Idx = MovePathIndex; - type Bit = MovePath<'tcx>; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); - fn name() -> &'static str { "maybe_init" } - fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.move_paths.len() - } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.move_paths[MovePathIndex::new(idx)] - } - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) - { - super::drop_flag_effects_for_function_entry( - ctxt.0, ctxt.1, &ctxt.2, - |path, s| { - assert!(s == DropFlagState::Present); - sets.on_entry.add(&path); - }); - } - - fn statement_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - idx: usize) - { - super::drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, - Location { block: bb, index: idx }, - |path, s| Self::update_bits(sets, path, s) - ) - } - - fn terminator_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - statements_len: usize) - { - super::drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, - Location { block: bb, index: statements_len }, - |path, s| Self::update_bits(sets, path, s) - ) - } - - fn propagate_call_return(&self, - ctxt: &Self::Ctxt, - in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { - // when a call returns successfully, that means we need to set - // the bits for that dest_lval to 1 (initialized). - let move_data = &ctxt.2; - let move_path_index = move_data.rev_lookup.find(dest_lval); - super::on_all_children_bits( - ctxt.0, ctxt.1, &ctxt.2, - move_path_index, - |mpi| { in_out.add(&mpi); } - ); - } -} - -impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { - type Idx = MovePathIndex; - type Bit = MovePath<'tcx>; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); - fn name() -> &'static str { "maybe_uninit" } - fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.move_paths.len() - } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.move_paths[MovePathIndex::new(idx)] - } - - // sets on_entry bits for Arg lvalues - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { - // set all bits to 1 (uninit) before gathering counterevidence - for e in sets.on_entry.words_mut() { *e = !0; } - - super::drop_flag_effects_for_function_entry( - ctxt.0, ctxt.1, &ctxt.2, - |path, s| { - assert!(s == DropFlagState::Present); - sets.on_entry.remove(&path); - }); - } - - fn statement_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - idx: usize) - { - super::drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, - Location { block: bb, index: idx }, - |path, s| Self::update_bits(sets, path, s) - ) - } - - fn terminator_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - statements_len: usize) - { - super::drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, - Location { block: bb, index: statements_len }, - |path, s| Self::update_bits(sets, path, s) - ) - } - - fn propagate_call_return(&self, - ctxt: &Self::Ctxt, - in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { - // when a call returns successfully, that means we need to set - // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.2.rev_lookup.find(dest_lval); - super::on_all_children_bits( - ctxt.0, ctxt.1, &ctxt.2, - move_path_index, - |mpi| { in_out.remove(&mpi); } - ); - } -} - -impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { - type Idx = MovePathIndex; - type Bit = MovePath<'tcx>; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); - fn name() -> &'static str { "definite_init" } - fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.move_paths.len() - } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.move_paths[MovePathIndex::new(idx)] - } - - // sets on_entry bits for Arg lvalues - fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { - for e in sets.on_entry.words_mut() { *e = 0; } - - super::drop_flag_effects_for_function_entry( - ctxt.0, ctxt.1, &ctxt.2, - |path, s| { - assert!(s == DropFlagState::Present); - sets.on_entry.add(&path); - }); - } - - fn statement_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - idx: usize) - { - super::drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, - Location { block: bb, index: idx }, - |path, s| Self::update_bits(sets, path, s) - ) - } - - fn terminator_effect(&self, - ctxt: &Self::Ctxt, - sets: &mut BlockSets, - bb: repr::BasicBlock, - statements_len: usize) - { - super::drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, - Location { block: bb, index: statements_len }, - |path, s| Self::update_bits(sets, path, s) - ) - } - - fn propagate_call_return(&self, - ctxt: &Self::Ctxt, - in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { - // when a call returns successfully, that means we need to set - // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.2.rev_lookup.find(dest_lval); - super::on_all_children_bits( - ctxt.0, ctxt.1, &ctxt.2, - move_path_index, - |mpi| { in_out.add(&mpi); } - ); - } -} - -fn zero_to_one(bitvec: &mut [usize], move_index: MoveOutIndex) { - let retval = bitvec.set_bit(move_index.idx()); - assert!(retval); -} - -impl<'a, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'tcx> { - #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { - pred1 | pred2 // moves from both preds are in scope - } -} - -impl<'a, 'tcx> BitwiseOperator for MaybeInitializedLvals<'a, 'tcx> { - #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { - pred1 | pred2 // "maybe" means we union effects of both preds - } -} - -impl<'a, 'tcx> BitwiseOperator for MaybeUninitializedLvals<'a, 'tcx> { - #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { - pred1 | pred2 // "maybe" means we union effects of both preds - } -} - -impl<'a, 'tcx> BitwiseOperator for DefinitelyInitializedLvals<'a, 'tcx> { - #[inline] - fn join(&self, pred1: usize, pred2: usize) -> usize { - pred1 & pred2 // "definitely" means we intersect effects of both preds - } -} - -// The way that dataflow fixed point iteration works, you want to -// start at bottom and work your way to a fixed point. Control-flow -// merges will apply the `join` operator to each block entry's current -// state (which starts at that bottom value). -// -// This means, for propagation across the graph, that you either want -// to start at all-zeroes and then use Union as your merge when -// propagating, or you start at all-ones and then use Intersect as -// your merge when propagating. - -impl<'a, 'tcx> DataflowOperator for MovingOutStatements<'a, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = no loans in scope by default - } -} - -impl<'a, 'tcx> DataflowOperator for MaybeInitializedLvals<'a, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = uninitialized - } -} - -impl<'a, 'tcx> DataflowOperator for MaybeUninitializedLvals<'a, 'tcx> { - #[inline] - fn bottom_value() -> bool { - false // bottom = initialized (start_block_effect counters this at outset) - } -} - -impl<'a, 'tcx> DataflowOperator for DefinitelyInitializedLvals<'a, 'tcx> { - #[inline] - fn bottom_value() -> bool { - true // bottom = initialized - } -} - From 644527d4dcb0fbd8333450dc5e2021aac8638252 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 24 May 2016 07:40:09 -0400 Subject: [PATCH 106/179] Move issue-26480 cfail to ui test. Fix #33763 --- .../run-make/unicode-input/span_length.rs | 65 +++++++++++++------ .../mismatched_types}/issue-26480.rs | 12 +--- .../ui/mismatched_types/issue-26480.stderr | 17 +++++ 3 files changed, 63 insertions(+), 31 deletions(-) rename src/test/{compile-fail => ui/mismatched_types}/issue-26480.rs (72%) create mode 100644 src/test/ui/mismatched_types/issue-26480.stderr diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index 3963d20df887..da8769e616c3 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rand, core)] +#![feature(rand)] use std::fs::File; use std::io::prelude::*; @@ -18,6 +18,11 @@ use std::process::Command; use std::__rand::{thread_rng, Rng}; use std::{char, env}; +pub fn check_old_skool() -> bool { + use std::env; + env::var("RUST_NEW_ERROR_FORMAT").is_err() +} + // creates a file with `fn main() { }` and checks the // compiler emits a span of the appropriate length (for the // "unresolved name" message); currently just using the number of code @@ -65,10 +70,17 @@ fn main() { let err = String::from_utf8_lossy(&result.stderr); - // the span should end the line (e.g no extra ~'s) - let expected_span = format!("^{}\n", repeat("~").take(n - 1) - .collect::()); - assert!(err.contains(&expected_span)); + if check_old_skool() { + // the span should end the line (e.g no extra ~'s) + let expected_span = format!("^{}\n", repeat("~").take(n - 1) + .collect::()); + assert!(err.contains(&expected_span)); + } else { + // the span should end the line (e.g no extra ~'s) + let expected_span = format!("^{}\n", repeat("^").take(n - 1) + .collect::()); + assert!(err.contains(&expected_span)); + } } // Test multi-column characters and tabs @@ -77,9 +89,6 @@ fn main() { r#"extern "路濫狼á́́" fn foo() {{}} extern "路濫狼á́" fn bar() {{}}"#); } - // Extra characters. Every line is preceded by `filename:lineno ` - let offset = main_file.to_str().unwrap().len() + 3; - let result = Command::new("sh") .arg("-c") .arg(format!("{} {}", @@ -91,17 +100,31 @@ fn main() { // Test both the length of the snake and the leading spaces up to it - // First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset) - let expected_span = format!("\n{}^{}\n", - repeat(" ").take(offset + 7).collect::(), - repeat("~").take(8).collect::()); - assert!(err.contains(&expected_span)); - // Second snake is only 7 ~s long, with 36 preceding spaces, - // because rustc counts chars() now rather than width(). This - // is because width() functions are to be removed from - // librustc_unicode - let expected_span = format!("\n{}^{}\n", - repeat(" ").take(offset + 36).collect::(), - repeat("~").take(7).collect::()); - assert!(err.contains(&expected_span)); + if check_old_skool() { + // Extra characters. Every line is preceded by `filename:lineno ` + let offset = main_file.to_str().unwrap().len() + 3; + + // First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset) + let expected_span = format!("\n{}^{}\n", + repeat(" ").take(offset + 7).collect::(), + repeat("~").take(8).collect::()); + assert!(err.contains(&expected_span)); + // Second snake is only 7 ~s long, with 36 preceding spaces, + // because rustc counts chars() now rather than width(). This + // is because width() functions are to be removed from + // librustc_unicode + let expected_span = format!("\n{}^{}\n", + repeat(" ").take(offset + 36).collect::(), + repeat("~").take(7).collect::()); + assert!(err.contains(&expected_span)); + } else { + let expected_span = format!("\n |>{}{}\n", + repeat(" ").take(8).collect::(), + repeat("^").take(9).collect::()); + assert!(err.contains(&expected_span)); + let expected_span = format!("\n |>{}{}\n", + repeat(" ").take(37).collect::(), + repeat("^").take(8).collect::()); + assert!(err.contains(&expected_span)); + } } diff --git a/src/test/compile-fail/issue-26480.rs b/src/test/ui/mismatched_types/issue-26480.rs similarity index 72% rename from src/test/compile-fail/issue-26480.rs rename to src/test/ui/mismatched_types/issue-26480.rs index 634a4014e118..516d92372e73 100644 --- a/src/test/compile-fail/issue-26480.rs +++ b/src/test/ui/mismatched_types/issue-26480.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// rustc-env:RUST_NEW_ERROR_FORMAT extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; } @@ -24,25 +25,16 @@ macro_rules! write { unsafe { write(stdout, $arr.as_ptr() as *const i8, $arr.len() * size_of($arr[0])); - //~^ ERROR mismatched types - //~| expected u64, found usize - //~| expected type - //~| found type } }} } macro_rules! cast { - ($x:expr) => ($x as ()) //~ ERROR non-scalar cast + ($x:expr) => ($x as ()) } fn main() { let hello = ['H', 'e', 'y']; write!(hello); - //~^ NOTE in this expansion of write! - //~| NOTE in this expansion of write! - //~| NOTE in this expansion of write! - cast!(2); - //~^ NOTE in this expansion of cast! } diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr new file mode 100644 index 000000000000..48bb546b382d --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -0,0 +1,17 @@ +error: mismatched types [--explain E0308] + --> $DIR/issue-26480.rs:27:19 + |> +27 |> $arr.len() * size_of($arr[0])); + |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize +$DIR/issue-26480.rs:38:5: 38:19: note: in this expansion of write! (defined in $DIR/issue-26480.rs) + + +error: non-scalar cast: `_` as `()` + --> $DIR/issue-26480.rs:33:19 + |> +33 |> ($x:expr) => ($x as ()) + |> ^^^^^^^^ +$DIR/issue-26480.rs:39:5: 39:14: note: in this expansion of cast! (defined in $DIR/issue-26480.rs) + + +error: aborting due to 2 previous errors From fbd66f8922b6000e5165283baf2938df247d5e5b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 24 May 2016 06:12:54 +0000 Subject: [PATCH 107/179] Add comments and fix a nit --- src/libsyntax/ext/expand.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index df1bbf5f26ec..596faac35882 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -35,10 +35,18 @@ use std_inject; use std::collections::HashSet; use std::env; +// A trait for AST nodes and AST node lists into which macro invocations may expand. trait MacroGenerable: Sized { + // Expand the given MacResult using its appropriate `make_*` method. fn make_with<'a>(result: Box) -> Option; + + // Fold this node or list of nodes using the given folder. fn fold_with(self, folder: &mut F) -> Self; + + // Return a placeholder expansion to allow compilation to continue after an erroring expansion. fn dummy(span: Span) -> Self; + + // The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics. fn kind_name() -> &'static str; } @@ -207,7 +215,7 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec { if ident.name != keywords::Invalid.name() { From 287d10a22c1089d2386ccb52440df80c87d9bd8f Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 18:22:03 +0200 Subject: [PATCH 108/179] syntax/hir: give loop labels a span This makes the "shadowing labels" warning *not* print the entire loop as a span, but only the lifetime. Also makes #31719 go away, but does not fix its root cause (the span of the expanded loop is still wonky, but not used anymore). --- src/librustc/hir/fold.rs | 8 ++++-- src/librustc/hir/intravisit.rs | 22 ++++++++------- src/librustc/hir/lowering.rs | 23 +++++++--------- src/librustc/hir/mod.rs | 4 +-- src/librustc/hir/print.rs | 12 ++++----- src/librustc/middle/resolve_lifetime.rs | 13 ++++----- src/librustc_incremental/calculate_svh.rs | 2 +- src/librustc_resolve/lib.rs | 6 ++--- src/libsyntax/ast.rs | 8 +++--- src/libsyntax/ext/expand.rs | 14 +++++----- src/libsyntax/fold.rs | 12 ++++++--- src/libsyntax/parse/parser.rs | 17 ++++++------ src/libsyntax/print/pprust.rs | 8 +++--- src/libsyntax/visit.rs | 33 +++++++++++++---------- 14 files changed, 99 insertions(+), 83 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index a91d16f25a2b..58f1006f98e6 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -1009,11 +1009,15 @@ pub fn noop_fold_expr(Expr { id, node, span, attrs }: Expr, folder: & ExprWhile(cond, body, opt_name) => { ExprWhile(folder.fold_expr(cond), folder.fold_block(body), - opt_name.map(|i| folder.fold_name(i))) + opt_name.map(|label| { + respan(folder.new_span(label.span), folder.fold_name(label.node)) + })) } ExprLoop(body, opt_name) => { ExprLoop(folder.fold_block(body), - opt_name.map(|i| folder.fold_name(i))) + opt_name.map(|label| { + respan(folder.new_span(label.span), folder.fold_name(label.node)) + })) } ExprMatch(expr, arms, source) => { ExprMatch(folder.fold_expr(expr), diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2e9e433b830f..9c61271fbfbd 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -28,7 +28,7 @@ use syntax::abi::Abi; use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::attr::ThinAttributesExt; -use syntax::codemap::Span; +use syntax::codemap::{Span, Spanned}; use hir::*; use std::cmp; @@ -203,11 +203,17 @@ pub trait Visitor<'v> : Sized { } pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { - for name in opt_name { + if let Some(name) = opt_name { visitor.visit_name(span, name); } } +pub fn walk_opt_sp_name<'v, V: Visitor<'v>>(visitor: &mut V, opt_sp_name: &Option>) { + if let Some(ref sp_name) = *opt_sp_name { + visitor.visit_name(sp_name.span, sp_name.node); + } +} + /// Walks the contents of a crate. See also `Crate::visit_all_items`. pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); @@ -737,14 +743,14 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprWhile(ref subexpression, ref block, opt_name) => { + ExprWhile(ref subexpression, ref block, ref opt_sp_name) => { visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_name(visitor, expression.span, opt_name) + walk_opt_sp_name(visitor, opt_sp_name); } - ExprLoop(ref block, opt_name) => { + ExprLoop(ref block, ref opt_sp_name) => { visitor.visit_block(block); - walk_opt_name(visitor, expression.span, opt_name) + walk_opt_sp_name(visitor, opt_sp_name); } ExprMatch(ref subexpression, ref arms, _) => { visitor.visit_expr(subexpression); @@ -784,9 +790,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_path(path, expression.id) } ExprBreak(ref opt_sp_name) | ExprAgain(ref opt_sp_name) => { - for sp_name in opt_sp_name { - visitor.visit_name(sp_name.span, sp_name.node); - } + walk_opt_sp_name(visitor, opt_sp_name); } ExprRet(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 28506fd20fe5..56777dc41d71 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -192,6 +192,10 @@ impl<'a> LoweringContext<'a> { } } + fn lower_opt_sp_ident(&mut self, o_id: Option>) -> Option> { + o_id.map(|sp_ident| respan(sp_ident.span, self.lower_ident(sp_ident.node))) + } + fn lower_attrs(&mut self, attrs: &Vec) -> hir::HirVec { attrs.clone().into() } @@ -1122,11 +1126,10 @@ impl<'a> LoweringContext<'a> { } ExprKind::While(ref cond, ref body, opt_ident) => { hir::ExprWhile(self.lower_expr(cond), self.lower_block(body), - opt_ident.map(|ident| self.lower_ident(ident))) + self.lower_opt_sp_ident(opt_ident)) } ExprKind::Loop(ref body, opt_ident) => { - hir::ExprLoop(self.lower_block(body), - opt_ident.map(|ident| self.lower_ident(ident))) + hir::ExprLoop(self.lower_block(body), self.lower_opt_sp_ident(opt_ident)) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(self.lower_expr(expr), @@ -1243,12 +1246,8 @@ impl<'a> LoweringContext<'a> { }; hir::ExprPath(hir_qself, self.lower_path_full(path, rename)) } - ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| { - respan(sp_ident.span, self.lower_ident(sp_ident.node)) - })), - ExprKind::Again(opt_ident) => hir::ExprAgain(opt_ident.map(|sp_ident| { - respan(sp_ident.span, self.lower_ident(sp_ident.node)) - })), + ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)), + ExprKind::Again(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))), ExprKind::InlineAsm(InlineAsm { ref inputs, @@ -1422,8 +1421,7 @@ impl<'a> LoweringContext<'a> { // `[opt_ident]: loop { ... }` let loop_block = self.block_expr(match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| self.lower_ident(ident))); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident)); // add attributes to the outer returned expr node let attrs = e.attrs.clone(); return P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs }); @@ -1503,8 +1501,7 @@ impl<'a> LoweringContext<'a> { // `[opt_ident]: loop { ... }` let loop_block = self.block_expr(match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| self.lower_ident(ident))); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident)); let loop_expr = P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: None }); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 39a6ec9f3af2..b147782316fd 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -873,11 +873,11 @@ pub enum Expr_ { /// A while loop, with an optional label /// /// `'label: while expr { block }` - ExprWhile(P, P, Option), + ExprWhile(P, P, Option>), /// Conditionless loop (can be exited with break, continue, or return) /// /// `'label: loop { block }` - ExprLoop(P, Option), + ExprLoop(P, Option>), /// A `match` block, with a source that indicates whether or not it is /// the result of a desugaring, and if so, which kind. ExprMatch(P, HirVec, MatchSource), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 4455c7da3ba3..74bc688d1548 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1351,9 +1351,9 @@ impl<'a> State<'a> { hir::ExprIf(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; } - hir::ExprWhile(ref test, ref blk, opt_name) => { - if let Some(name) = opt_name { - self.print_name(name)?; + hir::ExprWhile(ref test, ref blk, opt_sp_name) => { + if let Some(sp_name) = opt_sp_name { + self.print_name(sp_name.node)?; self.word_space(":")?; } self.head("while")?; @@ -1361,9 +1361,9 @@ impl<'a> State<'a> { space(&mut self.s)?; self.print_block(&blk)?; } - hir::ExprLoop(ref blk, opt_name) => { - if let Some(name) = opt_name { - self.print_name(name)?; + hir::ExprLoop(ref blk, opt_sp_name) => { + if let Some(sp_name) = opt_sp_name { + self.print_name(sp_name.node)?; self.word_space(":")?; } self.head("loop")?; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2200d72c883f..4cc9b0b4353a 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -404,23 +404,23 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { if let hir::ExprClosure(..) = ex.node { return } - if let Some(label) = expression_label(ex) { + if let Some((label, label_span)) = expression_label(ex) { for &(prior, prior_span) in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison if label == prior { signal_shadowing_problem(self.sess, label, original_label(prior_span), - shadower_label(ex.span)); + shadower_label(label_span)); } } check_if_label_shadows_lifetime(self.sess, self.scope, label, - ex.span); + label_span); - self.labels_in_fn.push((label, ex.span)); + self.labels_in_fn.push((label, label_span)); } intravisit::walk_expr(self, ex) } @@ -430,10 +430,11 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { } } - fn expression_label(ex: &hir::Expr) -> Option { + fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> { match ex.node { hir::ExprWhile(_, _, Some(label)) | - hir::ExprLoop(_, Some(label)) => Some(label.unhygienize()), + hir::ExprLoop(_, Some(label)) => Some((label.node.unhygienize(), + label.span)), _ => None, } } diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index 24ecce114874..3dd1b6eb205d 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -251,7 +251,7 @@ mod svh_visitor { ExprType(..) => SawExprType, ExprIf(..) => SawExprIf, ExprWhile(..) => SawExprWhile, - ExprLoop(_, id) => SawExprLoop(id.map(|id| id.as_str())), + ExprLoop(_, id) => SawExprLoop(id.map(|id| id.node.as_str())), ExprMatch(..) => SawExprMatch, ExprClosure(..) => SawExprClosure, ExprBlock(..) => SawExprBlock, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 41cc54628164..597a29d1aac6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3128,7 +3128,7 @@ impl<'a> Resolver<'a> { { let rib = this.label_ribs.last_mut().unwrap(); - rib.bindings.insert(mtwt::resolve(label), def); + rib.bindings.insert(mtwt::resolve(label.node), def); } visit::walk_expr(this, expr); @@ -3173,7 +3173,7 @@ impl<'a> Resolver<'a> { self.value_ribs.push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, RefutableMode, &mut HashMap::new()); - self.resolve_labeled_block(label, expr.id, block); + self.resolve_labeled_block(label.map(|l| l.node), expr.id, block); self.value_ribs.pop(); } @@ -3183,7 +3183,7 @@ impl<'a> Resolver<'a> { self.value_ribs.push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, LocalIrrefutableMode, &mut HashMap::new()); - self.resolve_labeled_block(label, expr.id, block); + self.resolve_labeled_block(label.map(|l| l.node), expr.id, block); self.value_ribs.pop(); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d9409d3bbd92..4a94d8b01a34 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1007,23 +1007,23 @@ pub enum ExprKind { /// A while loop, with an optional label /// /// `'label: while expr { block }` - While(P, P, Option), + While(P, P, Option), /// A while-let loop, with an optional label /// /// `'label: while let pat = expr { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - WhileLet(P, P, P, Option), + WhileLet(P, P, P, Option), /// A for loop, with an optional label /// /// `'label: for pat in expr { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - ForLoop(P, P, P, Option), + ForLoop(P, P, P, Option), /// Conditionless loop (can be exited with break, continue, or return) /// /// `'label: loop { block }` - Loop(P, Option), + Loop(P, Option), /// A `match` block. Match(P, Vec), /// A closure (for example, `move |a, b, c| {a + b + c}`) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 596faac35882..56374e935931 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast::{Block, Crate, DeclKind, PatKind}; -use ast::{Local, Ident, Mac_, Name}; +use ast::{Local, Ident, Mac_, Name, SpannedIdent}; use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind}; use ast::TokenTree; use ast; @@ -334,12 +334,12 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec, - opt_ident: Option, - fld: &mut MacroExpander) -> (P, Option) { + opt_ident: Option, + fld: &mut MacroExpander) -> (P, Option) { match opt_ident { Some(label) => { - let new_label = fresh_name(label); - let rename = (label, new_label); + let new_label = fresh_name(label.node); + let rename = (label.node, new_label); // The rename *must not* be added to the pending list of current // syntax context otherwise an unrelated `break` or `continue` in @@ -347,7 +347,7 @@ fn expand_loop_block(loop_block: P, // and be renamed incorrectly. let mut rename_list = vec!(rename); let mut rename_fld = IdentRenamer{renames: &mut rename_list}; - let renamed_ident = rename_fld.fold_ident(label); + let renamed_ident = rename_fld.fold_ident(label.node); // The rename *must* be added to the enclosed syntax context for // `break` or `continue` to pick up because by definition they are @@ -357,7 +357,7 @@ fn expand_loop_block(loop_block: P, let expanded_block = expand_block_elts(loop_block, fld); fld.cx.syntax_env.pop_frame(); - (expanded_block, Some(renamed_ident)) + (expanded_block, Some(Spanned { node: renamed_ident, span: label.span })) } None => (fld.fold_block(loop_block), opt_ident) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2c325080c0c2..f25be190537d 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1212,23 +1212,27 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::While(cond, body, opt_ident) => { ExprKind::While(folder.fold_expr(cond), folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::WhileLet(pat, expr, body, opt_ident) => { ExprKind::WhileLet(folder.fold_pat(pat), folder.fold_expr(expr), folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::ForLoop(pat, iter, body, opt_ident) => { ExprKind::ForLoop(folder.fold_pat(pat), folder.fold_expr(iter), folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::Loop(body, opt_ident) => { ExprKind::Loop(folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::Match(expr, arms) => { ExprKind::Match(folder.fold_expr(expr), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fc62cee92fdb..b616b9db9c3b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2283,18 +2283,19 @@ impl<'a> Parser<'a> { return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { - let lifetime = self.get_lifetime(); + let label = Spanned { node: self.get_lifetime(), + span: self.span }; let lo = self.span.lo; self.bump(); self.expect(&token::Colon)?; if self.eat_keyword(keywords::While) { - return self.parse_while_expr(Some(lifetime), lo, attrs) + return self.parse_while_expr(Some(label), lo, attrs) } if self.eat_keyword(keywords::For) { - return self.parse_for_expr(Some(lifetime), lo, attrs) + return self.parse_for_expr(Some(label), lo, attrs) } if self.eat_keyword(keywords::Loop) { - return self.parse_loop_expr(Some(lifetime), lo, attrs) + return self.parse_loop_expr(Some(label), lo, attrs) } return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } @@ -3264,7 +3265,7 @@ impl<'a> Parser<'a> { } /// Parse a 'for' .. 'in' expression ('for' token already eaten) - pub fn parse_for_expr(&mut self, opt_ident: Option, + pub fn parse_for_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { // Parse: `for in ` @@ -3283,7 +3284,7 @@ impl<'a> Parser<'a> { } /// Parse a 'while' or 'while let' expression ('while' token already eaten) - pub fn parse_while_expr(&mut self, opt_ident: Option, + pub fn parse_while_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { if self.token.is_keyword(keywords::Let) { @@ -3298,7 +3299,7 @@ impl<'a> Parser<'a> { } /// Parse a 'while let' expression ('while' token already eaten) - pub fn parse_while_let_expr(&mut self, opt_ident: Option, + pub fn parse_while_let_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { self.expect_keyword(keywords::Let)?; @@ -3312,7 +3313,7 @@ impl<'a> Parser<'a> { } // parse `loop {...}`, `loop` token already eaten - pub fn parse_loop_expr(&mut self, opt_ident: Option, + pub fn parse_loop_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ebb4927d69c0..fec84e912d49 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2021,7 +2021,7 @@ impl<'a> State<'a> { } ast::ExprKind::While(ref test, ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("while")?; @@ -2031,7 +2031,7 @@ impl<'a> State<'a> { } ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("while let")?; @@ -2044,7 +2044,7 @@ impl<'a> State<'a> { } ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("for")?; @@ -2057,7 +2057,7 @@ impl<'a> State<'a> { } ast::ExprKind::Loop(ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("loop")?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f50a480e5e55..3bd300a8e8c2 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -26,7 +26,7 @@ use abi::Abi; use ast::*; use attr::ThinAttributesExt; -use codemap::Span; +use codemap::{Span, Spanned}; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { @@ -149,17 +149,24 @@ macro_rules! walk_list { } pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { - for name in opt_name { + if let Some(name) = opt_name { visitor.visit_name(span, name); } } pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option) { - for ident in opt_ident { + if let Some(ident) = opt_ident { visitor.visit_ident(span, ident); } } +pub fn walk_opt_sp_ident<'v, V: Visitor<'v>>(visitor: &mut V, + opt_sp_ident: &Option>) { + if let Some(ref sp_ident) = *opt_sp_ident { + visitor.visit_ident(sp_ident.span, sp_ident.node); + } +} + pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { visitor.visit_name(span, ident.name); } @@ -712,10 +719,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprKind::While(ref subexpression, ref block, opt_ident) => { + ExprKind::While(ref subexpression, ref block, ref opt_sp_ident) => { visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { visitor.visit_pat(pattern); @@ -723,21 +730,21 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprKind::WhileLet(ref pattern, ref subexpression, ref block, opt_ident) => { + ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_sp_ident) => { visitor.visit_pat(pattern); visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } - ExprKind::ForLoop(ref pattern, ref subexpression, ref block, opt_ident) => { + ExprKind::ForLoop(ref pattern, ref subexpression, ref block, ref opt_sp_ident) => { visitor.visit_pat(pattern); visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } - ExprKind::Loop(ref block, opt_ident) => { + ExprKind::Loop(ref block, ref opt_sp_ident) => { visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } ExprKind::Match(ref subexpression, ref arms) => { visitor.visit_expr(subexpression); @@ -781,9 +788,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_path(path, expression.id) } ExprKind::Break(ref opt_sp_ident) | ExprKind::Again(ref opt_sp_ident) => { - for sp_ident in opt_sp_ident { - visitor.visit_ident(sp_ident.span, sp_ident.node); - } + walk_opt_sp_ident(visitor, opt_sp_ident); } ExprKind::Ret(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); From 81243afac79acb3e2116d8b00a6c495b09eca2b1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 15:01:48 +0200 Subject: [PATCH 109/179] move the `tcx` and `mir` parts of associated `Ctxt` onto each `BitDenotation` impl. --- .../borrowck/mir/dataflow/impls.rs | 118 +++++++++--------- .../borrowck/mir/dataflow/mod.rs | 12 +- src/librustc_borrowck/borrowck/mir/mod.rs | 26 ++-- 3 files changed, 77 insertions(+), 79 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index c9a23e3f288b..480b890da6ad 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -24,23 +24,9 @@ use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. use bitslice::{BitwiseOperator}; use indexed_set::{Idx, IdxSet}; -use std::marker::PhantomData; - // Dataflow analyses are built upon some interpretation of the // bitvectors attached to each basic block, represented via a // zero-sized structure. -// -// Note on PhantomData: Each interpretation will need to instantiate -// the `Bit` and `Ctxt` associated types, and in this case, those -// associated types need an associated lifetime `'tcx`. The -// interpretive structures are zero-sized, so they all need to carry a -// `PhantomData` representing how the structures relate to the `'tcx` -// lifetime. -// -// But, since all of the uses of `'tcx` are solely via instances of -// `Ctxt` that are passed into the `BitDenotation` methods, we can -// consistently use a `PhantomData` that is just a function over a -// `&Ctxt` (== `&MoveData<'tcx>). /// `MaybeInitializedLvals` tracks all l-values that might be /// initialized upon reaching a particular point in the control flow @@ -77,10 +63,15 @@ use std::marker::PhantomData; /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeUninitializedLvals` yields the set of /// l-values that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] pub struct MaybeInitializedLvals<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx: 'a> MaybeInitializedLvals<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { + MaybeInitializedLvals { tcx: tcx, mir: mir } + } } /// `MaybeUninitializedLvals` tracks all l-values that might be @@ -118,10 +109,15 @@ pub struct MaybeInitializedLvals<'a, 'tcx: 'a> { /// Similarly, at a given `drop` statement, the set-intersection /// between this data and `MaybeInitializedLvals` yields the set of /// l-values that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx: 'a> MaybeUninitializedLvals<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { + MaybeUninitializedLvals { tcx: tcx, mir: mir } + } } /// `DefinitelyInitializedLvals` tracks all l-values that are definitely @@ -165,10 +161,15 @@ pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> { /// Similarly, at a given `drop` statement, the set-difference between /// this data and `MaybeInitializedLvals` yields the set of l-values /// that would require a dynamic drop-flag at that statement. -#[derive(Debug, Default)] pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx: 'a> DefinitelyInitializedLvals<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { + DefinitelyInitializedLvals { tcx: tcx, mir: mir } + } } /// `MovingOutStatements` tracks the statements that perform moves out @@ -184,10 +185,10 @@ pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> { /// control flow. But `MovingOutStatements` also includes the added /// data of *which* particular statement causing the deinitialization /// that the borrow checker's error meessage may need to report. -#[derive(Debug, Default)] +#[allow(dead_code)] pub struct MovingOutStatements<'a, 'tcx: 'a> { - // See "Note on PhantomData" above. - phantom: PhantomData, TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>)> + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &'a Mir<'tcx>, } impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> { @@ -226,18 +227,18 @@ impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; type Bit = MovePath<'tcx>; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "maybe_init" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.move_paths.len() + ctxt.move_paths.len() } fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.move_paths[MovePathIndex::new(idx)] + &ctxt.move_paths[MovePathIndex::new(idx)] } fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { drop_flag_effects_for_function_entry( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, |path, s| { assert!(s == DropFlagState::Present); sets.on_entry.add(&path); @@ -251,7 +252,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { idx: usize) { drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, Location { block: bb, index: idx }, |path, s| Self::update_bits(sets, path, s) ) @@ -264,7 +265,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { statements_len: usize) { drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, Location { block: bb, index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) @@ -278,9 +279,8 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_data = &ctxt.2; - let move_path_index = move_data.rev_lookup.find(dest_lval); - on_all_children_bits(ctxt.0, ctxt.1, &ctxt.2, + let move_path_index = ctxt.rev_lookup.find(dest_lval); + on_all_children_bits(self.tcx, self.mir, ctxt, move_path_index, |mpi| { in_out.add(&mpi); }); } @@ -289,13 +289,13 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; type Bit = MovePath<'tcx>; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "maybe_uninit" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.move_paths.len() + ctxt.move_paths.len() } fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.move_paths[MovePathIndex::new(idx)] + &ctxt.move_paths[MovePathIndex::new(idx)] } // sets on_entry bits for Arg lvalues @@ -304,7 +304,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { for e in sets.on_entry.words_mut() { *e = !0; } drop_flag_effects_for_function_entry( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, |path, s| { assert!(s == DropFlagState::Present); sets.on_entry.remove(&path); @@ -318,7 +318,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { idx: usize) { drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, Location { block: bb, index: idx }, |path, s| Self::update_bits(sets, path, s) ) @@ -331,7 +331,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { statements_len: usize) { drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, Location { block: bb, index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) @@ -345,8 +345,8 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.2.rev_lookup.find(dest_lval); - on_all_children_bits(ctxt.0, ctxt.1, &ctxt.2, + let move_path_index = ctxt.rev_lookup.find(dest_lval); + on_all_children_bits(self.tcx, self.mir, ctxt, move_path_index, |mpi| { in_out.remove(&mpi); }); } @@ -355,13 +355,13 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; type Bit = MovePath<'tcx>; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "definite_init" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.move_paths.len() + ctxt.move_paths.len() } fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.move_paths[MovePathIndex::new(idx)] + &ctxt.move_paths[MovePathIndex::new(idx)] } // sets on_entry bits for Arg lvalues @@ -369,7 +369,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { for e in sets.on_entry.words_mut() { *e = 0; } drop_flag_effects_for_function_entry( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, |path, s| { assert!(s == DropFlagState::Present); sets.on_entry.add(&path); @@ -383,7 +383,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { idx: usize) { drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, Location { block: bb, index: idx }, |path, s| Self::update_bits(sets, path, s) ) @@ -396,7 +396,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { statements_len: usize) { drop_flag_effects_for_location( - ctxt.0, ctxt.1, &ctxt.2, + self.tcx, self.mir, ctxt, Location { block: bb, index: statements_len }, |path, s| Self::update_bits(sets, path, s) ) @@ -410,8 +410,8 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.2.rev_lookup.find(dest_lval); - on_all_children_bits(ctxt.0, ctxt.1, &ctxt.2, + let move_path_index = ctxt.rev_lookup.find(dest_lval); + on_all_children_bits(self.tcx, self.mir, ctxt, move_path_index, |mpi| { in_out.add(&mpi); }); } @@ -420,13 +420,13 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { type Idx = MoveOutIndex; type Bit = MoveOut; - type Ctxt = (TyCtxt<'a, 'tcx, 'tcx>, &'a Mir<'tcx>, MoveData<'tcx>); + type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "moving_out" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.2.moves.len() + ctxt.moves.len() } fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.2.moves[idx] + &ctxt.moves[idx] } fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { // no move-statements have been executed prior to function @@ -437,7 +437,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { sets: &mut BlockSets, bb: repr::BasicBlock, idx: usize) { - let &(tcx, mir, ref move_data) = ctxt; + let (tcx, mir, move_data) = (self.tcx, self.mir, ctxt); let stmt = &mir.basic_block_data(bb).statements[idx]; let loc_map = &move_data.loc_map; let path_map = &move_data.path_map; @@ -477,7 +477,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { bb: repr::BasicBlock, statements_len: usize) { - let &(_tcx, mir, ref move_data) = ctxt; + let (mir, move_data) = (self.mir, ctxt); let term = mir.basic_block_data(bb).terminator.as_ref().unwrap(); let loc_map = &move_data.loc_map; let loc = Location { block: bb, index: statements_len }; @@ -496,13 +496,13 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { _call_bb: repr::BasicBlock, _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { - let move_data = &ctxt.2; + let move_data = ctxt; let move_path_index = move_data.rev_lookup.find(dest_lval); let bits_per_block = self.bits_per_block(ctxt); let path_map = &move_data.path_map; - on_all_children_bits(ctxt.0, - ctxt.1, + on_all_children_bits(self.tcx, + self.mir, move_data, move_path_index, |mpi| for moi in &path_map[mpi] { diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 97e29fe064fe..e1470e62840d 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> } struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> - where O: 'b + BitDenotation, O::Ctxt: HasMoveData<'tcx> + where O: 'b + BitDenotation, O::Ctxt: 'a+HasMoveData<'tcx> { builder: &'b mut DataflowAnalysis<'a, 'tcx, O>, changed: bool, @@ -191,18 +191,18 @@ impl<'tcx, A, B> HasMoveData<'tcx> for (A, B, MoveData<'tcx>) { } pub struct DataflowAnalysis<'a, 'tcx: 'a, O> - where O: BitDenotation, O::Ctxt: HasMoveData<'tcx> + where O: BitDenotation, O::Ctxt: 'a+HasMoveData<'tcx> { flow_state: DataflowState, - ctxt: O::Ctxt, mir: &'a Mir<'tcx>, + ctxt: &'a O::Ctxt, } impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> where O: BitDenotation, O::Ctxt: HasMoveData<'tcx> { - pub fn results(self) -> (O::Ctxt, DataflowResults) { - (self.ctxt, DataflowResults(self.flow_state)) + pub fn results(self) -> DataflowResults { + DataflowResults(self.flow_state) } pub fn mir(&self) -> &'a Mir<'tcx> { self.mir } @@ -440,7 +440,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> { pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, - ctxt: D::Ctxt, + ctxt: &'a D::Ctxt, denotation: D) -> Self { let bits_per_block = denotation.bits_per_block(&ctxt); let usize_bits = mem::size_of::() * 8; diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 37c042844e58..54132cf0258d 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -75,24 +75,22 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( let tcx = bcx.tcx; let move_data = MoveData::gather_moves(mir, tcx); - let ctxt = (tcx, mir, move_data); - let (ctxt, flow_inits) = - do_dataflow(tcx, mir, id, attributes, ctxt, MaybeInitializedLvals::default()); - let (ctxt, flow_uninits) = - do_dataflow(tcx, mir, id, attributes, ctxt, MaybeUninitializedLvals::default()); - let (ctxt, flow_def_inits) = - do_dataflow(tcx, mir, id, attributes, ctxt, DefinitelyInitializedLvals::default()); + let flow_inits = + do_dataflow(tcx, mir, id, attributes, &move_data, MaybeInitializedLvals::new(tcx, mir)); + let flow_uninits = + do_dataflow(tcx, mir, id, attributes, &move_data, MaybeUninitializedLvals::new(tcx, mir)); + let flow_def_inits = + do_dataflow(tcx, mir, id, attributes, &move_data, DefinitelyInitializedLvals::new(tcx, mir)); if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() { - dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_inits); + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &move_data, &flow_inits); } if has_rustc_mir_with(attributes, "rustc_peek_maybe_uninit").is_some() { - dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_uninits); + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &move_data, &flow_uninits); } if has_rustc_mir_with(attributes, "rustc_peek_definite_init").is_some() { - dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &ctxt, &flow_def_inits); + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &move_data, &flow_def_inits); } - let move_data = ctxt.2; if has_rustc_mir_with(attributes, "stop_after_dataflow").is_some() { bcx.tcx.sess.fatal("stop_after_dataflow ended compilation"); @@ -118,8 +116,8 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, node_id: ast::NodeId, attributes: &[ast::Attribute], - ctxt: BD::Ctxt, - bd: BD) -> (BD::Ctxt, DataflowResults) + ctxt: &BD::Ctxt, + bd: BD) -> DataflowResults where BD: BitDenotation + DataflowOperator, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> { use syntax::attr::AttrMetaMethods; @@ -156,7 +154,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD> - where BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation, BD::Ctxt: 'a+HasMoveData<'tcx> { node_id: ast::NodeId, flow_state: DataflowAnalysis<'a, 'tcx, BD>, From c23bcf89b8a502900bf7a5bfc0174ceed3dc3494 Mon Sep 17 00:00:00 2001 From: Kamal Marhubi Date: Tue, 24 May 2016 16:08:01 +0200 Subject: [PATCH 110/179] syntax: Make codemap::get_filemap() return an Option This is more idiomatic, putting the caller in charge of whether or not to panic. --- src/librustc_driver/pretty.rs | 1 + src/libsyntax/codemap.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 8c84e561e317..0a093887c509 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -757,6 +757,7 @@ fn get_source(input: &Input, sess: &Session) -> (Vec, String) { let src_name = driver::source_name(input); let src = sess.codemap() .get_filemap(&src_name) + .unwrap() .src .as_ref() .unwrap() diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index ca8708fdc832..3b13bf2fc50b 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1191,13 +1191,13 @@ impl CodeMap { } } - pub fn get_filemap(&self, filename: &str) -> Rc { + pub fn get_filemap(&self, filename: &str) -> Option> { for fm in self.files.borrow().iter() { if filename == fm.name { - return fm.clone(); + return Some(fm.clone()); } } - panic!("asking for {} which we don't know about", filename); + None } /// For a global BytePos compute the local offset within the containing FileMap From c576152479f88b34e828069291ba95d2009b1f08 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 16:16:42 +0200 Subject: [PATCH 111/179] Replaced use of `interpret` method in `mir::dataflow::graphviz` with a client-provided closure. --- .../borrowck/mir/dataflow/graphviz.rs | 95 +++++++++++++++---- .../borrowck/mir/dataflow/mod.rs | 71 ++++---------- src/librustc_borrowck/borrowck/mir/mod.rs | 4 +- 3 files changed, 94 insertions(+), 76 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 5a8b3ec32062..8b7f04287bc2 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -21,15 +21,65 @@ use std::fs::File; use std::io; use std::io::prelude::*; use std::marker::PhantomData; +use std::mem; use std::path::Path; +use super::super::gather_moves::{MoveData}; use super::super::MirBorrowckCtxtPreDataflow; use bitslice::bits_to_string; +use indexed_set::{Idx, IdxSet}; use super::{BitDenotation, DataflowState}; -use super::{HasMoveData}; + +impl DataflowState { + fn each_bit(&self, ctxt: &O::Ctxt, words: &IdxSet, mut f: F) + where F: FnMut(O::Idx) { + //! Helper for iterating over the bits in a bitvector. + + let bits_per_block = self.operator.bits_per_block(ctxt); + let usize_bits: usize = mem::size_of::() * 8; + + for (word_index, &word) in words.words().iter().enumerate() { + if word != 0 { + let base_index = word_index * usize_bits; + for offset in 0..usize_bits { + let bit = 1 << offset; + if (word & bit) != 0 { + // NB: we round up the total number of bits + // that we store in any given bit set so that + // it is an even multiple of usize::BITS. This + // means that there may be some stray bits at + // the end that do not correspond to any + // actual value; that's why we first check + // that we are in range of bits_per_block. + let bit_index = base_index + offset as usize; + if bit_index >= bits_per_block { + return; + } else { + f(O::Idx::new(bit_index)); + } + } + } + } + } + } + + pub fn interpret_set<'c, P>(&self, + ctxt: &'c O::Ctxt, + words: &IdxSet, + render_idx: &P) + -> Vec<&'c Debug> + where P: for <'b> Fn(&'b O::Ctxt, O::Idx) -> &'b Debug + { + let mut v = Vec::new(); + self.each_bit(ctxt, words, |i| { + v.push(render_idx(ctxt, i)); + }); + v + } +} pub trait MirWithFlowState<'tcx> { - type BD: BitDenotation; + type BD: BitDenotation>; fn node_id(&self) -> NodeId; fn mir(&self) -> &Mir<'tcx>; fn analysis_ctxt(&self) -> &::Ctxt; @@ -37,7 +87,7 @@ pub trait MirWithFlowState<'tcx> { } impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where 'a, 'tcx: 'a, BD: BitDenotation, BD::Ctxt: HasMoveData<'tcx> + where 'a, 'tcx: 'a, BD: BitDenotation> { type BD = BD; fn node_id(&self) -> NodeId { self.node_id } @@ -46,19 +96,23 @@ impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, fn flow_state(&self) -> &DataflowState { &self.flow_state.flow_state } } -struct Graph<'a, 'tcx, MWF:'a> where MWF: MirWithFlowState<'tcx>, +struct Graph<'a, 'tcx, MWF:'a, P> where + MWF: MirWithFlowState<'tcx> { mbcx: &'a MWF, - phantom: PhantomData<&'tcx ()> + phantom: PhantomData<&'tcx ()>, + render_idx: P, } -pub fn print_borrowck_graph_to<'a, 'tcx, BD>( +pub fn print_borrowck_graph_to<'a, 'tcx, BD, P>( mbcx: &MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>, - path: &Path) + path: &Path, + render_idx: P) -> io::Result<()> - where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx>, + where BD: BitDenotation>, BD::Bit: Debug, + P: for <'b> Fn(&'b BD::Ctxt, BD::Idx) -> &'b Debug { - let g = Graph { mbcx: mbcx, phantom: PhantomData }; + let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx }; let mut v = Vec::new(); dot::render(&g, &mut v)?; debug!("print_borrowck_graph_to path: {} node_id: {}", @@ -76,8 +130,9 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec { (0..succ_len).map(|index| Edge { source: bb, index: index}).collect() } -impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> - where MWF: MirWithFlowState<'tcx>, ::Bit: Debug +impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> + where MWF: MirWithFlowState<'tcx>, ::Bit: Debug, + P: for <'b> Fn(&'b ::Ctxt, ::Idx) -> &'b Debug, { type Node = Node; type Edge = Edge; @@ -136,10 +191,10 @@ impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> const BG_FLOWCONTENT: &'static str = r#"bgcolor="pink""#; const ALIGN_RIGHT: &'static str = r#"align="right""#; const FACE_MONOSPACE: &'static str = r#"FACE="Courier""#; - fn chunked_present_left(w: &mut W, - interpreted: &[&D], - chunk_size: usize) - -> io::Result<()> + fn chunked_present_left(w: &mut W, + interpreted: &[&Debug], + chunk_size: usize) + -> io::Result<()> { // This function may emit a sequence of 's, but it // always finishes with an (unfinished) @@ -171,7 +226,9 @@ impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> |w| { let ctxt = self.mbcx.analysis_ctxt(); let flow = self.mbcx.flow_state(); - let entry_interp = flow.interpret_set(ctxt, flow.sets.on_entry_set_for(i)); + let entry_interp = flow.interpret_set(ctxt, + flow.sets.on_entry_set_for(i), + &self.render_idx); chunked_present_left(w, &entry_interp[..], chunk_size)?; let bits_per_block = flow.sets.bits_per_block(); let entry = flow.sets.on_entry_set_for(i); @@ -186,8 +243,8 @@ impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> |w| { let ctxt = self.mbcx.analysis_ctxt(); let flow = self.mbcx.flow_state(); - let gen_interp = flow.interpret_set(ctxt, flow.sets.gen_set_for(i)); - let kill_interp = flow.interpret_set(ctxt, flow.sets.kill_set_for(i)); + let gen_interp = flow.interpret_set(ctxt, flow.sets.gen_set_for(i), &self.render_idx); + let kill_interp = flow.interpret_set(ctxt, flow.sets.kill_set_for(i), &self.render_idx); chunked_present_left(w, &gen_interp[..], chunk_size)?; let bits_per_block = flow.sets.bits_per_block(); { @@ -245,7 +302,7 @@ impl<'a, 'tcx, MWF> dot::Labeller<'a> for Graph<'a, 'tcx, MWF> } } -impl<'a, 'tcx, MWF> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF> +impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> where MWF: MirWithFlowState<'tcx> { type Node = Node; diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index e1470e62840d..fb8d2ec39224 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -31,20 +31,19 @@ mod graphviz; mod sanity_check; mod impls; -pub trait Dataflow { - fn dataflow(&mut self); +pub trait Dataflow { + fn dataflow

(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug; } -impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation + DataflowOperator, +impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> + where BD: BitDenotation> + DataflowOperator, BD::Bit: Debug, - BD::Ctxt: HasMoveData<'tcx> { - fn dataflow(&mut self) { + fn dataflow

(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug { self.flow_state.build_sets(); - self.pre_dataflow_instrumentation().unwrap(); + self.pre_dataflow_instrumentation(|c,i| p(c,i)).unwrap(); self.flow_state.propagate(); - self.post_dataflow_instrumentation().unwrap(); + self.post_dataflow_instrumentation(|c,i| p(c,i)).unwrap(); } } @@ -142,21 +141,25 @@ fn dataflow_path(context: &str, prepost: &str, path: &str) -> PathBuf { } impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation>, BD::Bit: Debug { - fn pre_dataflow_instrumentation(&self) -> io::Result<()> { + fn pre_dataflow_instrumentation

(&self, p: P) -> io::Result<()> + where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug + { if let Some(ref path_str) = self.print_preflow_to { let path = dataflow_path(BD::name(), "preflow", path_str); - graphviz::print_borrowck_graph_to(self, &path) + graphviz::print_borrowck_graph_to(self, &path, p) } else { Ok(()) } } - fn post_dataflow_instrumentation(&self) -> io::Result<()> { + fn post_dataflow_instrumentation

(&self, p: P) -> io::Result<()> + where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug + { if let Some(ref path_str) = self.print_postflow_to { let path = dataflow_path(BD::name(), "postflow", path_str); - graphviz::print_borrowck_graph_to(self, &path) + graphviz::print_borrowck_graph_to(self, &path, p) } else{ Ok(()) } @@ -291,48 +294,6 @@ impl AllSets { } } -impl DataflowState { - fn each_bit(&self, ctxt: &O::Ctxt, words: &IdxSet, mut f: F) - where F: FnMut(usize) { - //! Helper for iterating over the bits in a bitvector. - - let bits_per_block = self.operator.bits_per_block(ctxt); - let usize_bits: usize = mem::size_of::() * 8; - - for (word_index, &word) in words.words().iter().enumerate() { - if word != 0 { - let base_index = word_index * usize_bits; - for offset in 0..usize_bits { - let bit = 1 << offset; - if (word & bit) != 0 { - // NB: we round up the total number of bits - // that we store in any given bit set so that - // it is an even multiple of usize::BITS. This - // means that there may be some stray bits at - // the end that do not correspond to any - // actual value; that's why we first check - // that we are in range of bits_per_block. - let bit_index = base_index + offset as usize; - if bit_index >= bits_per_block { - return; - } else { - f(bit_index); - } - } - } - } - } - } - - pub fn interpret_set<'c>(&self, ctxt: &'c O::Ctxt, words: &IdxSet) -> Vec<&'c O::Bit> { - let mut v = Vec::new(); - self.each_bit(ctxt, words, |i| { - v.push(self.operator.interpret(ctxt, i)); - }); - v - } -} - /// Parameterization for the precise form of data flow that is used. pub trait DataflowOperator: BitwiseOperator { /// Specifies the initial value for each bit in the `on_entry` set diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 54132cf0258d..92f8f91b9308 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -118,7 +118,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, attributes: &[ast::Attribute], ctxt: &BD::Ctxt, bd: BD) -> DataflowResults - where BD: BitDenotation + DataflowOperator, BD::Bit: Debug, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation> + DataflowOperator, BD::Bit: Debug { use syntax::attr::AttrMetaMethods; @@ -148,7 +148,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, flow_state: DataflowAnalysis::new(tcx, mir, ctxt, bd), }; - mbcx.dataflow(); + mbcx.dataflow(|move_data, i| &move_data.move_paths[i]); mbcx.flow_state.results() } From 358850e919d1d3a2aff6be704b8e87e44ed32926 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 24 May 2016 10:42:32 -0400 Subject: [PATCH 112/179] Back to single line between errors. Add header space to secondary files --- src/libsyntax/errors/emitter.rs | 6 +++++- src/libsyntax/errors/snippet/mod.rs | 7 +++++++ src/libsyntax/errors/snippet/test.rs | 14 ++++++++++++++ src/test/ui/mismatched_types/issue-26480.stderr | 2 -- src/test/ui/mismatched_types/main.stderr | 1 - 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 2ba003c5eafb..6b15aa4f92c5 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -238,7 +238,7 @@ impl EmitterWriter { self.first = false; } else { if !self.old_school { - write!(self.dst, "\n\n")?; + write!(self.dst, "\n")?; } } } @@ -682,6 +682,7 @@ mod test { println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" --> dummy.txt:11:1 + |> 11 |> e-lä-vän |> ^ "#[1..]); @@ -746,6 +747,7 @@ mod test { let expect_start = &r#" --> dummy.txt:1:6 + |> 1 |> _____aaaaaa____bbbbbb__cccccdd_ |> ^^^^^^ ^^^^^^ ^^^^^^^ "#[1..]; @@ -818,6 +820,7 @@ mod test { let expect0 = &r#" --> dummy.txt:5:1 + |> 5 |> ccccc |> ^ ... @@ -830,6 +833,7 @@ mod test { let expect = &r#" --> dummy.txt:1:1 + |> 1 |> aaaaa |> ^ ... diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 414da87b749c..2a43a14ddf87 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -494,6 +494,13 @@ impl FileInfo { }], kind: RenderedLineKind::OtherFileName, }); + output.push(RenderedLine { + text: vec![StyledString { + text: "".to_string(), + style: Style::FileNameStyle, + }], + kind: RenderedLineKind::Annotations, + }); } } } diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 62ce3fa9dd5e..51fe4572dbc6 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -98,6 +98,7 @@ fn foo() { let text = make_string(&lines); assert_eq!(&text[..], &" --> foo.rs:3:2 + |> 3 |> \tbar; |> \t^^^ "[1..]); @@ -130,6 +131,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ::: foo.rs + |> 3 |> vec.push(vec.pop().unwrap()); |> --- --- - previous borrow ends here |> | | @@ -199,12 +201,14 @@ fn bar() { // Note that the `|>` remain aligned across both files: assert_eq!(&text[..], &r#" --> foo.rs:3:14 + |> 3 |> vec.push(vec.pop().unwrap()); |> --- ^^^ - c |> | | |> | b |> a ::: bar.rs + |> 17 |> vec.push(); |> --- - f |> | @@ -249,6 +253,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ::: foo.rs + |> 3 |> let name = find_id(&data, 22).unwrap(); |> ---- immutable borrow begins here ... @@ -288,6 +293,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ::: foo.rs + |> 3 |> vec.push(vec.pop().unwrap()); |> -------- ------ D |> || @@ -324,6 +330,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ::: foo.rs + |> 3 |> vec.push(vec.pop().unwrap()); |> --- --- - previous borrow ends here |> | | @@ -362,6 +369,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ::: foo.rs + |> 4 |> let mut vec2 = vec; |> --- `vec` moved here because it has type `collections::vec::Vec` ... @@ -398,6 +406,7 @@ fn foo() { println!("text=&r#\"\n{}\n\"#[1..]", text); assert_eq!(text, &r#" ::: foo.rs + |> 3 |> let mut vec = vec![0, 1, 2]; |> --- --- 4 |> let mut vec2 = vec; @@ -429,6 +438,7 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs + |> 3 |> fn foo(x: u32) { |> - "#[1..]); @@ -458,6 +468,7 @@ fn span_overlap_label() { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs + |> 2 |> fn foo(x: u32) { |> -------------- |> | | @@ -492,6 +503,7 @@ fn span_overlap_label2() { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs + |> 2 |> fn foo(x: u32) { |> -------------- |> | | @@ -537,6 +549,7 @@ fn span_overlap_label3() { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ::: foo.rs + |> 3 |> let closure = || { |> - foo 4 |> inner @@ -577,6 +590,7 @@ fn main() { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" --> foo.rs:11:2 + |> 11 |> } |> - "#[1..]); diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 48bb546b382d..c00594a59c11 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -5,7 +5,6 @@ error: mismatched types [--explain E0308] |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize $DIR/issue-26480.rs:38:5: 38:19: note: in this expansion of write! (defined in $DIR/issue-26480.rs) - error: non-scalar cast: `_` as `()` --> $DIR/issue-26480.rs:33:19 |> @@ -13,5 +12,4 @@ error: non-scalar cast: `_` as `()` |> ^^^^^^^^ $DIR/issue-26480.rs:39:5: 39:14: note: in this expansion of cast! (defined in $DIR/issue-26480.rs) - error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 0e68c0d0b135..1af332ee5bea 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -6,5 +6,4 @@ error: mismatched types [--explain E0308] note: expected type `u32` note: found type `()` - error: aborting due to previous error From 9e7e6742f0818bc252157b97eca8d36129dd9ac0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 16:46:19 +0200 Subject: [PATCH 113/179] Removed `type Bit` and `fn interpret` items from `trait BitDenotation`. Also got rid of the `trait HasMoveData`, since I am now just imposing the constraint that `BitDenotation>` where necessary instead. --- .../borrowck/mir/dataflow/graphviz.rs | 4 +- .../borrowck/mir/dataflow/impls.rs | 20 ++-------- .../borrowck/mir/dataflow/mod.rs | 39 +++++-------------- .../borrowck/mir/dataflow/sanity_check.rs | 13 +++---- src/librustc_borrowck/borrowck/mir/mod.rs | 7 +--- 5 files changed, 21 insertions(+), 62 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 8b7f04287bc2..0d1443ede410 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -109,7 +109,7 @@ pub fn print_borrowck_graph_to<'a, 'tcx, BD, P>( path: &Path, render_idx: P) -> io::Result<()> - where BD: BitDenotation>, BD::Bit: Debug, + where BD: BitDenotation>, P: for <'b> Fn(&'b BD::Ctxt, BD::Idx) -> &'b Debug { let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx }; @@ -131,7 +131,7 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec { } impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> - where MWF: MirWithFlowState<'tcx>, ::Bit: Debug, + where MWF: MirWithFlowState<'tcx>, P: for <'b> Fn(&'b ::Ctxt, ::Idx) -> &'b Debug, { type Node = Node; diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 480b890da6ad..c580dc8551f2 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -12,7 +12,7 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir}; use super::super::gather_moves::{Location}; -use super::super::gather_moves::{MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex}; +use super::super::gather_moves::{MoveData, MoveOutIndex, MovePathIndex}; use super::super::DropFlagState; use super::super::drop_flag_effects_for_function_entry; use super::super::drop_flag_effects_for_location; @@ -226,15 +226,12 @@ impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; - type Bit = MovePath<'tcx>; type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "maybe_init" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { ctxt.move_paths.len() } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.move_paths[MovePathIndex::new(idx)] - } + fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { drop_flag_effects_for_function_entry( @@ -288,15 +285,11 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; - type Bit = MovePath<'tcx>; type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "maybe_uninit" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { ctxt.move_paths.len() } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.move_paths[MovePathIndex::new(idx)] - } // sets on_entry bits for Arg lvalues fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { @@ -354,15 +347,11 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; - type Bit = MovePath<'tcx>; type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "definite_init" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { ctxt.move_paths.len() } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.move_paths[MovePathIndex::new(idx)] - } // sets on_entry bits for Arg lvalues fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) { @@ -419,15 +408,12 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { type Idx = MoveOutIndex; - type Bit = MoveOut; type Ctxt = MoveData<'tcx>; fn name() -> &'static str { "moving_out" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { ctxt.moves.len() } - fn interpret<'c>(&self, ctxt: &'c Self::Ctxt, idx: usize) -> &'c Self::Bit { - &ctxt.moves[idx] - } + fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { // no move-statements have been executed prior to function // execution, so this method has no effect on `_sets`. diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index fb8d2ec39224..f91bd88d68f0 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -36,8 +36,7 @@ pub trait Dataflow { } impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation> + DataflowOperator, - BD::Bit: Debug, + where BD: BitDenotation> + DataflowOperator { fn dataflow

(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug { self.flow_state.build_sets(); @@ -48,14 +47,14 @@ impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> } struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> - where O: 'b + BitDenotation, O::Ctxt: 'a+HasMoveData<'tcx> + where O: 'b + BitDenotation, O::Ctxt: 'a { builder: &'b mut DataflowAnalysis<'a, 'tcx, O>, changed: bool, } impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> - where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation + DataflowOperator { fn propagate(&mut self) { let mut temp = OwnIdxSet::new_empty(self.flow_state.sets.bits_per_block); @@ -102,7 +101,7 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> } impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> - where BD: BitDenotation + DataflowOperator, BD::Ctxt: HasMoveData<'tcx> + where BD: BitDenotation + DataflowOperator { fn reset(&mut self, bits: &mut IdxSet) { let e = if BD::bottom_value() {!0} else {0}; @@ -141,7 +140,7 @@ fn dataflow_path(context: &str, prepost: &str, path: &str) -> PathBuf { } impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation>, BD::Bit: Debug + where BD: BitDenotation> { fn pre_dataflow_instrumentation

(&self, p: P) -> io::Result<()> where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug @@ -182,19 +181,8 @@ impl Bits { } } -pub trait HasMoveData<'tcx> { - fn move_data(&self) -> &MoveData<'tcx>; -} - -impl<'tcx> HasMoveData<'tcx> for MoveData<'tcx> { - fn move_data(&self) -> &MoveData<'tcx> { self } -} -impl<'tcx, A, B> HasMoveData<'tcx> for (A, B, MoveData<'tcx>) { - fn move_data(&self) -> &MoveData<'tcx> { &self.2 } -} - pub struct DataflowAnalysis<'a, 'tcx: 'a, O> - where O: BitDenotation, O::Ctxt: 'a+HasMoveData<'tcx> + where O: BitDenotation, O::Ctxt: 'a { flow_state: DataflowState, mir: &'a Mir<'tcx>, @@ -202,7 +190,7 @@ pub struct DataflowAnalysis<'a, 'tcx: 'a, O> } impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> - where O: BitDenotation, O::Ctxt: HasMoveData<'tcx> + where O: BitDenotation { pub fn results(self) -> DataflowResults { DataflowResults(self.flow_state) @@ -301,9 +289,6 @@ pub trait DataflowOperator: BitwiseOperator { } pub trait BitDenotation { - /// Specifies what is represented by each bit in the dataflow bitvector. - type Bit; - /// Specifies what index type is used to access the bitvector. type Idx: Idx; @@ -322,10 +307,6 @@ pub trait BitDenotation { /// Size of each bitvector allocated for each block in the analysis. fn bits_per_block(&self, &Self::Ctxt) -> usize; - /// Provides the meaning of each entry in the dataflow bitvector. - /// (Mostly intended for use for better debug instrumentation.) - fn interpret<'a>(&self, &'a Self::Ctxt, idx: usize) -> &'a Self::Bit; - /// Mutates the block-sets (the flow sets for the given /// basic block) according to the effects that have been /// established *prior* to entering the start block. @@ -396,8 +377,7 @@ pub trait BitDenotation { } impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> - where D: BitDenotation + DataflowOperator, - D::Ctxt: HasMoveData<'tcx> + where D: BitDenotation + DataflowOperator { pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, @@ -439,8 +419,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> } impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> - where D: BitDenotation + DataflowOperator, - D::Ctxt: HasMoveData<'tcx>, + where D: BitDenotation + DataflowOperator { /// Propagates the bits of `in_out` into all the successors of `bb`, /// using bitwise operator denoted by `self.operator`. diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 932975b88084..221768994942 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -15,10 +15,9 @@ use syntax::codemap::Span; use rustc::ty::{self, TyCtxt}; use rustc::mir::repr::{self, Mir}; -use super::super::gather_moves::{MovePath, MovePathIndex}; +use super::super::gather_moves::{MoveData, MovePathIndex}; use super::BitDenotation; use super::DataflowResults; -use super::HasMoveData; /// This function scans `mir` for all calls to the intrinsic /// `rustc_peek` that have the expression form `rustc_peek(&expr)`. @@ -42,7 +41,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _attributes: &[ast::Attribute], flow_ctxt: &O::Ctxt, results: &DataflowResults) - where O: BitDenotation, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx> + where O: BitDenotation, Idx=MovePathIndex> { debug!("sanity_check_via_rustc_peek id: {:?}", id); // FIXME: this is not DRY. Figure out way to abstract this and @@ -57,10 +56,10 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, - flow_ctxt: &O::Ctxt, + move_data: &O::Ctxt, results: &DataflowResults, bb: repr::BasicBlock) where - O: BitDenotation, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx> + O: BitDenotation, Idx=MovePathIndex> { let bb_data = mir.basic_block_data(bb); let &repr::BasicBlockData { ref statements, @@ -88,8 +87,6 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned(); let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned(); - let move_data = flow_ctxt.move_data(); - // Emulate effect of all statements in the block up to (but not // including) the borrow within `peek_arg_lval`. Do *not* include // call to `peek_arg_lval` itself (since we are peeking the state @@ -138,7 +135,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // reset GEN and KILL sets before emulating their effect. for e in sets.gen_set.words_mut() { *e = 0; } for e in sets.kill_set.words_mut() { *e = 0; } - results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j); + results.0.operator.statement_effect(move_data, &mut sets, bb, j); sets.on_entry.union(sets.gen_set); sets.on_entry.subtract(sets.kill_set); } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 92f8f91b9308..4b77e4c865b5 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -31,14 +31,11 @@ mod gather_moves; use self::dataflow::{BitDenotation}; use self::dataflow::{DataflowOperator}; use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; -use self::dataflow::{HasMoveData}; use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use self::dataflow::{DefinitelyInitializedLvals}; use self::gather_moves::{MoveData, MovePathIndex, Location}; use self::gather_moves::{MovePathContent}; -use std::fmt::Debug; - fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option> { for attr in attrs { if attr.check_name("rustc_mir") { @@ -118,7 +115,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, attributes: &[ast::Attribute], ctxt: &BD::Ctxt, bd: BD) -> DataflowResults - where BD: BitDenotation> + DataflowOperator, BD::Bit: Debug + where BD: BitDenotation> + DataflowOperator { use syntax::attr::AttrMetaMethods; @@ -154,7 +151,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD> - where BD: BitDenotation, BD::Ctxt: 'a+HasMoveData<'tcx> + where BD: BitDenotation, BD::Ctxt: 'a { node_id: ast::NodeId, flow_state: DataflowAnalysis<'a, 'tcx, BD>, From 51b1e797c5ae41e5d43b3bbeab866c3e7450ae22 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 24 May 2016 10:57:44 -0400 Subject: [PATCH 114/179] Satisfy tidy --- src/test/compile-fail/issue-33819.rs | 9 +++++++++ src/test/ui/mismatched_types/issue-26480.rs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-33819.rs b/src/test/compile-fail/issue-33819.rs index 418e66dbd4d3..9c9677c1e986 100644 --- a/src/test/compile-fail/issue-33819.rs +++ b/src/test/compile-fail/issue-33819.rs @@ -1,3 +1,12 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. fn main() { let mut op = Some(2); match op { diff --git a/src/test/ui/mismatched_types/issue-26480.rs b/src/test/ui/mismatched_types/issue-26480.rs index 516d92372e73..96db31f4b116 100644 --- a/src/test/ui/mismatched_types/issue-26480.rs +++ b/src/test/ui/mismatched_types/issue-26480.rs @@ -30,7 +30,7 @@ macro_rules! write { } macro_rules! cast { - ($x:expr) => ($x as ()) + ($x:expr) => ($x as ()) } fn main() { From 5e1f56ba21008b3d0b22fa44fa9b23902646243a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 17 May 2016 11:57:07 -0700 Subject: [PATCH 115/179] std: Stabilize APIs for the 1.10 release This commit applies the FCP decisions made by the libs team for the 1.10 cycle, including both new stabilizations and deprecations. Specifically, the list of APIs is: Stabilized: * `os::windows::fs::OpenOptionsExt::access_mode` * `os::windows::fs::OpenOptionsExt::share_mode` * `os::windows::fs::OpenOptionsExt::custom_flags` * `os::windows::fs::OpenOptionsExt::attributes` * `os::windows::fs::OpenOptionsExt::security_qos_flags` * `os::unix::fs::OpenOptionsExt::custom_flags` * `sync::Weak::new` * `Default for sync::Weak` * `panic::set_hook` * `panic::take_hook` * `panic::PanicInfo` * `panic::PanicInfo::payload` * `panic::PanicInfo::location` * `panic::Location` * `panic::Location::file` * `panic::Location::line` * `ffi::CStr::from_bytes_with_nul` * `ffi::CStr::from_bytes_with_nul_unchecked` * `ffi::FromBytesWithNulError` * `fs::Metadata::modified` * `fs::Metadata::accessed` * `fs::Metadata::created` * `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange` * `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak` * `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key` * `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}` * `SocketAddr::is_unnamed` * `SocketAddr::as_pathname` * `UnixStream::connect` * `UnixStream::pair` * `UnixStream::try_clone` * `UnixStream::local_addr` * `UnixStream::peer_addr` * `UnixStream::set_read_timeout` * `UnixStream::set_write_timeout` * `UnixStream::read_timeout` * `UnixStream::write_Timeout` * `UnixStream::set_nonblocking` * `UnixStream::take_error` * `UnixStream::shutdown` * Read/Write/RawFd impls for `UnixStream` * `UnixListener::bind` * `UnixListener::accept` * `UnixListener::try_clone` * `UnixListener::local_addr` * `UnixListener::set_nonblocking` * `UnixListener::take_error` * `UnixListener::incoming` * RawFd impls for `UnixListener` * `UnixDatagram::bind` * `UnixDatagram::unbound` * `UnixDatagram::pair` * `UnixDatagram::connect` * `UnixDatagram::try_clone` * `UnixDatagram::local_addr` * `UnixDatagram::peer_addr` * `UnixDatagram::recv_from` * `UnixDatagram::recv` * `UnixDatagram::send_to` * `UnixDatagram::send` * `UnixDatagram::set_read_timeout` * `UnixDatagram::set_write_timeout` * `UnixDatagram::read_timeout` * `UnixDatagram::write_timeout` * `UnixDatagram::set_nonblocking` * `UnixDatagram::take_error` * `UnixDatagram::shutdown` * RawFd impls for `UnixDatagram` * `{BTree,Hash}Map::values_mut` * `<[_]>::binary_search_by_key` Deprecated: * `StaticCondvar` - this, and all other static synchronization primitives below, are usable today through the lazy-static crate on stable Rust today. Additionally, we'd like the non-static versions to be directly usable in a static context one day, so they're unlikely to be the final forms of the APIs in any case. * `CONDVAR_INIT` * `StaticMutex` * `MUTEX_INIT` * `StaticRwLock` * `RWLOCK_INIT` * `iter::Peekable::is_empty` Closes #27717 Closes #27720 cc #27784 (but encode methods still exist) Closes #30014 Closes #30425 Closes #30449 Closes #31190 Closes #31399 Closes #31767 Closes #32111 Closes #32281 Closes #32312 Closes #32551 Closes #33018 --- src/liballoc/arc.rs | 61 ++-- src/liballoc/lib.rs | 1 - src/liballoc/rc.rs | 59 ++-- src/libcollections/btree/map.rs | 19 +- src/libcollections/lib.rs | 1 - src/libcollections/slice.rs | 3 +- src/libcollectionstest/lib.rs | 2 - src/libcore/char.rs | 6 +- src/libcore/iter/mod.rs | 1 + src/libcore/slice.rs | 9 +- src/libcore/sync/atomic.rs | 18 +- src/libcoretest/iter.rs | 135 +++----- src/libcoretest/lib.rs | 1 - src/liblog/lib.rs | 50 +-- src/librustc_back/dynamic_lib.rs | 10 +- src/librustc_back/lib.rs | 1 - src/libstd/collections/hash/map.rs | 17 +- src/libstd/ffi/c_str.rs | 37 +- src/libstd/ffi/mod.rs | 2 + src/libstd/fs.rs | 6 +- src/libstd/io/lazy.rs | 21 +- src/libstd/panic.rs | 2 +- src/libstd/panicking.rs | 31 +- src/libstd/sync/condvar.rs | 24 ++ src/libstd/sync/mod.rs | 4 + src/libstd/sync/mutex.rs | 28 +- src/libstd/sync/rwlock.rs | 31 +- src/libstd/sys/common/args.rs | 16 +- .../unix/backtrace/tracing/backtrace_fn.rs | 28 +- .../sys/unix/backtrace/tracing/gcc_s.rs | 36 +- src/libstd/sys/unix/ext/fs.rs | 4 +- src/libstd/sys/unix/ext/net.rs | 72 +++- src/libstd/sys/unix/fs.rs | 35 +- src/libstd/sys/unix/os.rs | 52 +-- src/libstd/sys/unix/time.rs | 318 +++++++----------- src/libstd/sys/windows/ext/fs.rs | 19 +- src/libstd/sys/windows/process.rs | 27 +- 37 files changed, 615 insertions(+), 572 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 4aba567fa1c2..d0a51e320cc2 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -592,6 +592,31 @@ impl Drop for Arc { } } +impl Weak { + /// Constructs a new `Weak` without an accompanying instance of T. + /// + /// This allocates memory for T, but does not initialize it. Calling + /// Weak::upgrade() on the return value always gives None. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Weak; + /// + /// let empty: Weak = Weak::new(); + /// ``` + #[stable(feature = "downgraded_weak", since = "1.10.0")] + pub fn new() -> Weak { + unsafe { + Weak { ptr: Shared::new(Box::into_raw(box ArcInner { + strong: atomic::AtomicUsize::new(0), + weak: atomic::AtomicUsize::new(1), + data: uninitialized(), + }))} + } + } +} + impl Weak { /// Upgrades a weak reference to a strong reference. /// @@ -682,6 +707,13 @@ impl Clone for Weak { } } +#[stable(feature = "downgraded_weak", since = "1.10.0")] +impl Default for Weak { + fn default() -> Weak { + Weak::new() + } +} + #[stable(feature = "arc_weak", since = "1.4.0")] impl Drop for Weak { /// Drops the `Weak`. @@ -907,35 +939,6 @@ impl From for Arc { } } -impl Weak { - /// Constructs a new `Weak` without an accompanying instance of T. - /// - /// This allocates memory for T, but does not initialize it. Calling - /// Weak::upgrade() on the return value always gives None. - /// - /// # Examples - /// - /// ``` - /// #![feature(downgraded_weak)] - /// - /// use std::sync::Weak; - /// - /// let empty: Weak = Weak::new(); - /// ``` - #[unstable(feature = "downgraded_weak", - reason = "recently added", - issue = "30425")] - pub fn new() -> Weak { - unsafe { - Weak { ptr: Shared::new(Box::into_raw(box ArcInner { - strong: atomic::AtomicUsize::new(0), - weak: atomic::AtomicUsize::new(1), - data: uninitialized(), - }))} - } - } -} - #[cfg(test)] mod tests { use std::clone::Clone; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index c2dad9a1ae4f..0293d5402c4c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -90,7 +90,6 @@ #![feature(unique)] #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(unsize)] -#![feature(extended_compare_and_swap)] #![cfg_attr(not(test), feature(raw, fn_traits, placement_new_protocol))] #![cfg_attr(test, feature(test, box_heap))] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c2f0a9613273..b92f5af05e31 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -720,6 +720,33 @@ impl !marker::Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Weak {} +impl Weak { + /// Constructs a new `Weak` without an accompanying instance of T. + /// + /// This allocates memory for T, but does not initialize it. Calling + /// Weak::upgrade() on the return value always gives None. + /// + /// # Examples + /// + /// ``` + /// use std::rc::Weak; + /// + /// let empty: Weak = Weak::new(); + /// ``` + #[stable(feature = "downgraded_weak", since = "1.10.0")] + pub fn new() -> Weak { + unsafe { + Weak { + ptr: Shared::new(Box::into_raw(box RcBox { + strong: Cell::new(0), + weak: Cell::new(1), + value: uninitialized(), + })), + } + } + } +} + impl Weak { /// Upgrades a weak reference to a strong reference. /// @@ -823,34 +850,10 @@ impl fmt::Debug for Weak { } } -impl Weak { - /// Constructs a new `Weak` without an accompanying instance of T. - /// - /// This allocates memory for T, but does not initialize it. Calling - /// Weak::upgrade() on the return value always gives None. - /// - /// # Examples - /// - /// ``` - /// #![feature(downgraded_weak)] - /// - /// use std::rc::Weak; - /// - /// let empty: Weak = Weak::new(); - /// ``` - #[unstable(feature = "downgraded_weak", - reason = "recently added", - issue="30425")] - pub fn new() -> Weak { - unsafe { - Weak { - ptr: Shared::new(Box::into_raw(box RcBox { - strong: Cell::new(0), - weak: Cell::new(1), - value: uninitialized(), - })), - } - } +#[stable(feature = "downgraded_weak", since = "1.10.0")] +impl Default for Weak { + fn default() -> Weak { + Weak::new() } } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 844940020066..ec2f4a9f7f0b 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -286,7 +286,7 @@ pub struct Values<'a, K: 'a, V: 'a> { } /// A mutable iterator over a BTreeMap's values. -#[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] +#[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } @@ -1144,7 +1144,7 @@ impl<'a, K, V> Iterator for Range<'a, K, V> { } } -#[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] +#[stable(feature = "map_values_mut", since = "1.10.0")] impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; @@ -1157,14 +1157,14 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { } } -#[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] +#[stable(feature = "map_values_mut", since = "1.10.0")] impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> { fn next_back(&mut self) -> Option<&'a mut V> { self.inner.next_back().map(|(_, v)| v) } } -#[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] +#[stable(feature = "map_values_mut", since = "1.10.0")] impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { fn len(&self) -> usize { self.inner.len() @@ -1575,7 +1575,6 @@ impl BTreeMap { /// Basic usage: /// /// ``` - /// # #![feature(map_values_mut)] /// use std::collections::BTreeMap; /// /// let mut a = BTreeMap::new(); @@ -1590,8 +1589,8 @@ impl BTreeMap { /// assert_eq!(values, [String::from("hello!"), /// String::from("goodbye!")]); /// ``` - #[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] - pub fn values_mut<'a>(&'a mut self) -> ValuesMut<'a, K, V> { + #[stable(feature = "map_values_mut", since = "1.10.0")] + pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut() } } @@ -1656,7 +1655,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. - #[unstable(feature = "map_entry_keys", issue = "32281")] + #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { Occupied(ref entry) => entry.key(), @@ -1668,7 +1667,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. - #[unstable(feature = "map_entry_keys", issue = "32281")] + #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { &self.key } @@ -1718,7 +1717,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the key in the entry. - #[unstable(feature = "map_entry_keys", issue = "32281")] + #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { self.handle.reborrow().into_kv().0 } diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 34e4a426d3c0..6ab66fc217b4 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -27,7 +27,6 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(not(test), feature(slice_binary_search_by_key))] // impl [T] #![cfg_attr(not(stage0), deny(warnings))] #![feature(alloc)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6321d5924d51..cef8a33703b7 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -759,7 +759,6 @@ impl [T] { /// fourth could match any position in `[1,4]`. /// /// ```rust - /// #![feature(slice_binary_search_by_key)] /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), /// (1, 21), (2, 34), (4, 55)]; @@ -770,7 +769,7 @@ impl [T] { /// let r = s.binary_search_by_key(&1, |&(a,b)| b); /// assert!(match r { Ok(1...4) => true, _ => false, }); /// ``` - #[unstable(feature = "slice_binary_search_by_key", reason = "recently added", issue = "33018")] + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] pub fn binary_search_by_key(&self, b: &B, f: F) -> Result where F: FnMut(&T) -> B, diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index e4152b99d2c6..bae21f1bd9b8 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -22,8 +22,6 @@ #![feature(enumset)] #![feature(iter_arith)] #![feature(linked_list_contains)] -#![feature(map_entry_keys)] -#![feature(map_values_mut)] #![feature(pattern)] #![feature(rand)] #![feature(step_by)] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 65b9a27bb68e..6a2331dddcf0 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -15,11 +15,9 @@ #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] -use iter::Iterator; +use prelude::v1::*; + use mem::transmute; -use option::Option::{None, Some}; -use option::Option; -use slice::SliceExt; // UTF-8 ranges and tags for encoding characters const TAG_CONT: u8 = 0b1000_0000; diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 17f7c0a773e6..f964527b4b41 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1125,6 +1125,7 @@ impl Peekable { /// ``` #[unstable(feature = "peekable_is_empty", issue = "32111")] #[inline] + #[rustc_deprecated(since = "1.10.0", reason = "replaced by .peek().is_none()")] pub fn is_empty(&mut self) -> bool { self.peek().is_none() } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 542dfcbe6284..a0e978f783d7 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -106,6 +106,10 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn binary_search_by(&self, f: F) -> Result where F: FnMut(&Self::Item) -> Ordering; + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + fn binary_search_by_key(&self, b: &B, f: F) -> Result + where F: FnMut(&Self::Item) -> B, + B: Ord; #[stable(feature = "core", since = "1.6.0")] fn len(&self) -> usize; #[stable(feature = "core", since = "1.6.0")] @@ -157,11 +161,6 @@ pub trait SliceExt { fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone; #[stable(feature = "copy_from_slice", since = "1.9.0")] fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; - - #[unstable(feature = "slice_binary_search_by_key", reason = "recently added", issue = "33018")] - fn binary_search_by_key(&self, b: &B, f: F) -> Result - where F: FnMut(&Self::Item) -> B, - B: Ord; } // Use macros to be generic over const/mut diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 1bdab88d71da..d0a64de07e51 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -299,7 +299,6 @@ impl AtomicBool { /// # Examples /// /// ``` - /// # #![feature(extended_compare_and_swap)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let some_bool = AtomicBool::new(true); @@ -318,7 +317,7 @@ impl AtomicBool { /// assert_eq!(some_bool.load(Ordering::Relaxed), false); /// ``` #[inline] - #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")] + #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] pub fn compare_exchange(&self, current: bool, new: bool, @@ -347,7 +346,6 @@ impl AtomicBool { /// # Examples /// /// ``` - /// # #![feature(extended_compare_and_swap)] /// use std::sync::atomic::{AtomicBool, Ordering}; /// /// let val = AtomicBool::new(false); @@ -362,7 +360,7 @@ impl AtomicBool { /// } /// ``` #[inline] - #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")] + #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] pub fn compare_exchange_weak(&self, current: bool, new: bool, @@ -645,7 +643,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// # #![feature(extended_compare_and_swap)] /// use std::sync::atomic::{AtomicPtr, Ordering}; /// /// let ptr = &mut 5; @@ -658,7 +655,7 @@ impl AtomicPtr { /// Ordering::SeqCst, Ordering::Relaxed); /// ``` #[inline] - #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")] + #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] pub fn compare_exchange(&self, current: *mut T, new: *mut T, @@ -693,7 +690,6 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// # #![feature(extended_compare_and_swap)] /// use std::sync::atomic::{AtomicPtr, Ordering}; /// /// let some_ptr = AtomicPtr::new(&mut 5); @@ -708,7 +704,7 @@ impl AtomicPtr { /// } /// ``` #[inline] - #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")] + #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] pub fn compare_exchange_weak(&self, current: *mut T, new: *mut T, @@ -901,7 +897,6 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// # #![feature(extended_compare_and_swap)] /// use std::sync::atomic::{AtomicIsize, Ordering}; /// /// let some_isize = AtomicIsize::new(5); @@ -945,7 +940,6 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// # #![feature(extended_compare_and_swap)] /// use std::sync::atomic::{AtomicIsize, Ordering}; /// /// let val = AtomicIsize::new(4); @@ -1115,14 +1109,14 @@ atomic_int! { #[cfg(any(stage0, target_has_atomic = "ptr"))] atomic_int!{ stable(feature = "rust1", since = "1.0.0"), - unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767"), + stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), isize AtomicIsize ATOMIC_ISIZE_INIT } #[cfg(any(stage0, target_has_atomic = "ptr"))] atomic_int!{ stable(feature = "rust1", since = "1.0.0"), - unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767"), + stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), usize AtomicUsize ATOMIC_USIZE_INIT } diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index 37884dd26e3e..54fca291e5ec 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -9,7 +9,7 @@ // except according to those terms. use core::iter::*; -use core::{i16, i8, isize}; +use core::{i8, i16, isize}; use core::usize; use test::Bencher; @@ -17,52 +17,52 @@ use test::Bencher; #[test] fn test_lt() { let empty: [isize; 0] = []; - let xs = [1, 2, 3]; - let ys = [1, 2, 0]; + let xs = [1,2,3]; + let ys = [1,2,0]; assert!(!xs.iter().lt(ys.iter())); assert!(!xs.iter().le(ys.iter())); - assert!(xs.iter().gt(ys.iter())); - assert!(xs.iter().ge(ys.iter())); + assert!( xs.iter().gt(ys.iter())); + assert!( xs.iter().ge(ys.iter())); - assert!(ys.iter().lt(xs.iter())); - assert!(ys.iter().le(xs.iter())); + assert!( ys.iter().lt(xs.iter())); + assert!( ys.iter().le(xs.iter())); assert!(!ys.iter().gt(xs.iter())); assert!(!ys.iter().ge(xs.iter())); - assert!(empty.iter().lt(xs.iter())); - assert!(empty.iter().le(xs.iter())); + assert!( empty.iter().lt(xs.iter())); + assert!( empty.iter().le(xs.iter())); assert!(!empty.iter().gt(xs.iter())); assert!(!empty.iter().ge(xs.iter())); // Sequence with NaN let u = [1.0f64, 2.0]; - let v = [0.0f64 / 0.0, 3.0]; + let v = [0.0f64/0.0, 3.0]; assert!(!u.iter().lt(v.iter())); assert!(!u.iter().le(v.iter())); assert!(!u.iter().gt(v.iter())); assert!(!u.iter().ge(v.iter())); - let a = [0.0f64 / 0.0]; + let a = [0.0f64/0.0]; let b = [1.0f64]; let c = [2.0f64]; - assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); + assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); assert!(a.iter().le(b.iter()) == (a[0] <= b[0])); - assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); + assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); assert!(a.iter().ge(b.iter()) == (a[0] >= b[0])); - assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); + assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); assert!(c.iter().le(b.iter()) == (c[0] <= b[0])); - assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); + assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); assert!(c.iter().ge(b.iter()) == (c[0] >= b[0])); } #[test] fn test_multi_iter() { - let xs = [1, 2, 3, 4]; - let ys = [4, 3, 2, 1]; + let xs = [1,2,3,4]; + let ys = [4,3,2,1]; assert!(xs.iter().eq(ys.iter().rev())); assert!(xs.iter().lt(xs.iter().skip(2))); } @@ -148,18 +148,9 @@ fn test_iterator_chain_find() { #[test] fn test_filter_map() { - let it = (0..) - .step_by(1) - .take(10) - .filter_map(|x| { - if x % 2 == 0 { - Some(x * x) - } else { - None - } - }); - assert_eq!(it.collect::>(), - [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]); + let it = (0..).step_by(1).take(10) + .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None }); + assert_eq!(it.collect::>(), [0*0, 2*2, 4*4, 6*6, 8*8]); } #[test] @@ -319,7 +310,7 @@ fn test_iterator_skip() { while let Some(&x) = it.next() { assert_eq!(x, ys[i]); i += 1; - assert_eq!(it.len(), xs.len() - 5 - i); + assert_eq!(it.len(), xs.len()-5-i); } assert_eq!(i, ys.len()); assert_eq!(it.len(), 0); @@ -416,7 +407,7 @@ fn test_iterator_take() { while let Some(&x) = it.next() { assert_eq!(x, ys[i]); i += 1; - assert_eq!(it.len(), 5 - i); + assert_eq!(it.len(), 5-i); } assert_eq!(i, ys.len()); assert_eq!(it.len(), 0); @@ -456,7 +447,7 @@ fn test_iterator_take_short() { while let Some(&x) = it.next() { assert_eq!(x, ys[i]); i += 1; - assert_eq!(it.len(), 4 - i); + assert_eq!(it.len(), 4-i); } assert_eq!(i, ys.len()); assert_eq!(it.len(), 0); @@ -593,10 +584,9 @@ fn test_iterator_size_hint() { assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None)); assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None)); assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None)); - assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), - (usize::MAX, None)); + assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None)); assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10))); - assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None)); + assert_eq!(c.clone().scan(0, |_,_| Some(0)).size_hint(), (0, None)); assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None)); assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None)); assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None)); @@ -610,10 +600,9 @@ fn test_iterator_size_hint() { assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10))); assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13))); assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3))); - assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), - (0, Some(10))); + assert_eq!(vi.clone().scan(0, |_,_| Some(0)).size_hint(), (0, Some(10))); assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10))); + assert_eq!(vi.clone().map(|&i| i+1).size_hint(), (10, Some(10))); assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10))); } @@ -695,7 +684,8 @@ fn test_rev() { let mut it = xs.iter(); it.next(); it.next(); - assert!(it.rev().cloned().collect::>() == vec![16, 14, 12, 10, 8, 6]); + assert!(it.rev().cloned().collect::>() == + vec![16, 14, 12, 10, 8, 6]); } #[test] @@ -768,13 +758,7 @@ fn test_double_ended_filter() { #[test] fn test_double_ended_filter_map() { let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().filter_map(|&x| { - if x & 1 == 0 { - Some(x * 2) - } else { - None - } - }); + let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None }); assert_eq!(it.next_back().unwrap(), 12); assert_eq!(it.next_back().unwrap(), 8); assert_eq!(it.next().unwrap(), 4); @@ -799,20 +783,11 @@ fn test_double_ended_chain() { // test that .chain() is well behaved with an unfused iterator struct CrazyIterator(bool); - impl CrazyIterator { - fn new() -> CrazyIterator { - CrazyIterator(false) - } - } + impl CrazyIterator { fn new() -> CrazyIterator { CrazyIterator(false) } } impl Iterator for CrazyIterator { type Item = i32; fn next(&mut self) -> Option { - if self.0 { - Some(99) - } else { - self.0 = true; - None - } + if self.0 { Some(99) } else { self.0 = true; None } } } @@ -828,14 +803,8 @@ fn test_double_ended_chain() { #[test] fn test_rposition() { - fn f(xy: &(isize, char)) -> bool { - let (_x, y) = *xy; - y == 'b' - } - fn g(xy: &(isize, char)) -> bool { - let (_x, y) = *xy; - y == 'd' - } + fn f(xy: &(isize, char)) -> bool { let (_x, y) = *xy; y == 'b' } + fn g(xy: &(isize, char)) -> bool { let (_x, y) = *xy; y == 'd' } let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; assert_eq!(v.iter().rposition(f), Some(3)); @@ -845,7 +814,9 @@ fn test_rposition() { #[test] #[should_panic] fn test_rposition_panic() { - let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), (box 0, box 0), (box 0, box 0)]; + let v: [(Box<_>, Box<_>); 4] = + [(box 0, box 0), (box 0, box 0), + (box 0, box 0), (box 0, box 0)]; let mut i = 0; v.iter().rposition(|_elt| { if i == 2 { @@ -859,18 +830,18 @@ fn test_rposition_panic() { #[test] fn test_double_ended_flat_map() { - let u = [0, 1]; - let v = [5, 6, 7, 8]; + let u = [0,1]; + let v = [5,6,7,8]; let mut it = u.iter().flat_map(|x| &v[*x..v.len()]); assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.next().unwrap(), &5); assert_eq!(it.next_back().unwrap(), &7); assert_eq!(it.next_back().unwrap(), &6); assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &6); + assert_eq!(it.next().unwrap(), &6); assert_eq!(it.next_back().unwrap(), &7); assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); + assert_eq!(it.next(), None); assert_eq!(it.next_back(), None); } @@ -890,8 +861,7 @@ fn test_double_ended_range() { #[test] fn test_range() { assert_eq!((0..5).collect::>(), [0, 1, 2, 3, 4]); - assert_eq!((-10..-1).collect::>(), - [-10, -9, -8, -7, -6, -5, -4, -3, -2]); + assert_eq!((-10..-1).collect::>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]); assert_eq!((0..5).rev().collect::>(), [4, 3, 2, 1, 0]); assert_eq!((200..-5).count(), 0); assert_eq!((200..-5).rev().count(), 0); @@ -927,12 +897,9 @@ fn test_range_step() { assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0))); assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0))); assert_eq!((0..1).step_by(0).size_hint(), (0, None)); - assert_eq!((i8::MAX..i8::MIN).step_by(i8::MIN).size_hint(), - (2, Some(2))); - assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX).size_hint(), - (3, Some(3))); - assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), - (usize::MAX, Some(usize::MAX))); + assert_eq!((i8::MAX..i8::MIN).step_by(i8::MIN).size_hint(), (2, Some(2))); + assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX).size_hint(), (3, Some(3))); + assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); } #[test] @@ -1018,11 +985,7 @@ fn bench_skip_while(b: &mut Bencher) { b.iter(|| { let it = 0..100; let mut sum = 0; - it.skip_while(|&x| { - sum += x; - sum < 4000 - }) - .all(|_| true); + it.skip_while(|&x| { sum += x; sum < 4000 }).all(|_| true); }); } @@ -1037,9 +1000,7 @@ fn bench_multiple_take(b: &mut Bencher) { }); } -fn scatter(x: i32) -> i32 { - (x * 31) % 127 -} +fn scatter(x: i32) -> i32 { (x * 31) % 127 } #[bench] fn bench_max_by_key(b: &mut Bencher) { diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 603dda2c96d2..88d73df937f7 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -24,7 +24,6 @@ #![feature(iter_arith)] #![feature(libc)] #![feature(nonzero)] -#![feature(peekable_is_empty)] #![feature(rand)] #![feature(raw)] #![feature(slice_patterns)] diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 011f5a744dc8..a71f6efe54eb 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -170,10 +170,7 @@ #![deny(missing_docs)] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(box_syntax)] -#![feature(const_fn)] #![feature(staged_api)] -#![feature(static_mutex)] use std::cell::RefCell; use std::fmt; @@ -181,9 +178,8 @@ use std::io::{self, Stderr}; use std::io::prelude::*; use std::mem; use std::env; -use std::ptr; use std::slice; -use std::sync::{Once, StaticMutex}; +use std::sync::{Once, Mutex, ONCE_INIT}; use directive::LOG_LEVEL_NAMES; @@ -199,18 +195,13 @@ pub const MAX_LOG_LEVEL: u32 = 255; /// The default logging level of a crate if no other is specified. const DEFAULT_LOG_LEVEL: u32 = 1; -static LOCK: StaticMutex = StaticMutex::new(); +static mut LOCK: *mut Mutex<(Vec, Option)> = 0 as *mut _; /// An unsafe constant that is the maximum logging level of any module /// specified. This is the first line of defense to determining whether a /// logging statement should be run. static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; -static mut DIRECTIVES: *mut Vec = ptr::null_mut(); - -/// Optional filter. -static mut FILTER: *mut String = ptr::null_mut(); - /// Debug log level pub const DEBUG: u32 = 4; /// Info log level @@ -287,14 +278,10 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // Test the literal string from args against the current filter, if there // is one. unsafe { - let _g = LOCK.lock(); - match FILTER as usize { - 0 => {} - n => { - let filter = mem::transmute::<_, &String>(n); - if !args.to_string().contains(filter) { - return; - } + let filter = (*LOCK).lock().unwrap(); + if let Some(ref filter) = filter.1 { + if !args.to_string().contains(filter) { + return; } } } @@ -302,10 +289,10 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // Completely remove the local logger from TLS in case anyone attempts to // frob the slot while we're doing the logging. This will destroy any logger // set during logging. - let mut logger: Box = LOCAL_LOGGER.with(|s| s.borrow_mut().take()) - .unwrap_or_else(|| { - box DefaultLogger { handle: io::stderr() } - }); + let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); + let mut logger = logger.unwrap_or_else(|| { + Box::new(DefaultLogger { handle: io::stderr() }) + }); logger.log(&LogRecord { level: LogLevel(level), args: args, @@ -363,7 +350,7 @@ pub struct LogLocation { /// module's log statement should be emitted or not. #[doc(hidden)] pub fn mod_enabled(level: u32, module: &str) -> bool { - static INIT: Once = Once::new(); + static INIT: Once = ONCE_INIT; INIT.call_once(init); // It's possible for many threads are in this function, only one of them @@ -378,10 +365,9 @@ pub fn mod_enabled(level: u32, module: &str) -> bool { // This assertion should never get tripped unless we're in an at_exit // handler after logging has been torn down and a logging attempt was made. - let _g = LOCK.lock(); unsafe { - assert!(DIRECTIVES as usize != 0); - enabled(level, module, (*DIRECTIVES).iter()) + let directives = (*LOCK).lock().unwrap(); + enabled(level, module, directives.0.iter()) } } @@ -422,14 +408,8 @@ fn init() { unsafe { LOG_LEVEL = max_level; - assert!(FILTER.is_null()); - match filter { - Some(f) => FILTER = Box::into_raw(box f), - None => {} - } - - assert!(DIRECTIVES.is_null()); - DIRECTIVES = Box::into_raw(box directives); + assert!(LOCK.is_null()); + LOCK = Box::into_raw(Box::new(Mutex::new((directives, filter)))); } } diff --git a/src/librustc_back/dynamic_lib.rs b/src/librustc_back/dynamic_lib.rs index 2f86262afbe2..38e60060925e 100644 --- a/src/librustc_back/dynamic_lib.rs +++ b/src/librustc_back/dynamic_lib.rs @@ -189,12 +189,16 @@ mod dl { pub fn check_for_errors_in(f: F) -> Result where F: FnOnce() -> T, { - use std::sync::StaticMutex; - static LOCK: StaticMutex = StaticMutex::new(); + use std::sync::{Mutex, Once, ONCE_INIT}; + static INIT: Once = ONCE_INIT; + static mut LOCK: *mut Mutex<()> = 0 as *mut _; unsafe { + INIT.call_once(|| { + LOCK = Box::into_raw(Box::new(Mutex::new(()))); + }); // dlerror isn't thread safe, so we need to lock around this entire // sequence - let _guard = LOCK.lock(); + let _guard = (*LOCK).lock(); let _old_error = libc::dlerror(); let result = f(); diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 67b11a930d6f..6a7bc51d15a4 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -38,7 +38,6 @@ #![feature(staged_api)] #![feature(step_by)] #![feature(question_mark)] -#![cfg_attr(unix, feature(static_mutex))] #![cfg_attr(test, feature(test, rand))] extern crate syntax; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e0a489bd2f96..37045822d47e 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -864,7 +864,6 @@ impl HashMap /// # Examples /// /// ``` - /// # #![feature(map_values_mut)] /// use std::collections::HashMap; /// /// let mut map = HashMap::new(); @@ -881,8 +880,8 @@ impl HashMap /// print!("{}", val); /// } /// ``` - #[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] - pub fn values_mut<'a>(&'a mut self) -> ValuesMut { + #[stable(feature = "map_values_mut", since = "1.10.0")] + pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut() } } @@ -1288,7 +1287,7 @@ pub struct Drain<'a, K: 'a, V: 'a> { } /// Mutable HashMap values iterator. -#[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] +#[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V> } @@ -1491,14 +1490,14 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -#[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] +#[stable(feature = "map_values_mut", since = "1.10.0")] impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; #[inline] fn next(&mut self) -> Option<(&'a mut V)> { self.inner.next().map(|(_, v)| v) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } -#[unstable(feature = "map_values_mut", reason = "recently added", issue = "32551")] +#[stable(feature = "map_values_mut", since = "1.10.0")] impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } @@ -1537,7 +1536,7 @@ impl<'a, K, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. - #[unstable(feature = "map_entry_keys", issue = "32281")] + #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { Occupied(ref entry) => entry.key(), @@ -1548,7 +1547,7 @@ impl<'a, K, V> Entry<'a, K, V> { impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the key in the entry. - #[unstable(feature = "map_entry_keys", issue = "32281")] + #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { self.elem.read().0 } @@ -1596,7 +1595,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. - #[unstable(feature = "map_entry_keys", issue = "32281")] + #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { &self.key } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index fbc8886ce8f8..2bc7585f5fba 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -159,6 +159,12 @@ pub struct CStr { #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); +/// An error returned from `CStr::from_bytes_with_nul` to indicate that a nul +/// byte was found too early in the slice provided or one wasn't found at all. +#[derive(Clone, PartialEq, Debug)] +#[stable(feature = "cstr_from_bytes", since = "1.10.0")] +pub struct FromBytesWithNulError { _a: () } + /// An error returned from `CString::into_string` to indicate that a UTF-8 error /// was encountered during the conversion. #[derive(Clone, PartialEq, Debug)] @@ -461,20 +467,18 @@ impl CStr { /// # Examples /// /// ``` - /// # #![feature(cstr_from_bytes)] /// use std::ffi::CStr; /// - /// # fn main() { /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); - /// assert!(cstr.is_some()); - /// # } + /// assert!(cstr.is_ok()); /// ``` - #[unstable(feature = "cstr_from_bytes", reason = "recently added", issue = "31190")] - pub fn from_bytes_with_nul(bytes: &[u8]) -> Option<&CStr> { + #[stable(feature = "cstr_from_bytes", since = "1.10.0")] + pub fn from_bytes_with_nul(bytes: &[u8]) + -> Result<&CStr, FromBytesWithNulError> { if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) { - None + Err(FromBytesWithNulError { _a: () }) } else { - Some(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) + Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) } } @@ -487,18 +491,15 @@ impl CStr { /// # Examples /// /// ``` - /// # #![feature(cstr_from_bytes)] /// use std::ffi::{CStr, CString}; /// - /// # fn main() { /// unsafe { /// let cstring = CString::new("hello").unwrap(); /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); /// assert_eq!(cstr, &*cstring); /// } - /// # } /// ``` - #[unstable(feature = "cstr_from_bytes", reason = "recently added", issue = "31190")] + #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { mem::transmute(bytes) } @@ -742,12 +743,14 @@ mod tests { fn from_bytes_with_nul() { let data = b"123\0"; let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes), Some(&b"123"[..])); - assert_eq!(cstr.map(CStr::to_bytes_with_nul), Some(&b"123\0"[..])); + assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); unsafe { + let cstr = CStr::from_bytes_with_nul(data); let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); - assert_eq!(cstr, Some(cstr_unchecked)); + assert_eq!(cstr, Ok(cstr_unchecked)); } } @@ -755,13 +758,13 @@ mod tests { fn from_bytes_with_nul_unterminated() { let data = b"123"; let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_none()); + assert!(cstr.is_err()); } #[test] fn from_bytes_with_nul_interior() { let data = b"1\023\0"; let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_none()); + assert!(cstr.is_err()); } } diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index bfd6ab52289b..ca1ff18f1cad 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -14,6 +14,8 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use self::c_str::{CString, CStr, NulError, IntoStringError}; +#[stable(feature = "cstr_from_bytes", since = "1.10.0")] +pub use self::c_str::{FromBytesWithNulError}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::os_str::{OsString, OsStr}; diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 587c7a95861c..125170bd47bc 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -657,7 +657,7 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. - #[unstable(feature = "fs_time", issue = "31399")] + #[stable(feature = "fs_time", since = "1.10.0")] pub fn modified(&self) -> io::Result { self.0.modified().map(FromInner::from_inner) } @@ -675,7 +675,7 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. - #[unstable(feature = "fs_time", issue = "31399")] + #[stable(feature = "fs_time", since = "1.10.0")] pub fn accessed(&self) -> io::Result { self.0.accessed().map(FromInner::from_inner) } @@ -689,7 +689,7 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. - #[unstable(feature = "fs_time", issue = "31399")] + #[stable(feature = "fs_time", since = "1.10.0")] pub fn created(&self) -> io::Result { self.0.created().map(FromInner::from_inner) } diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 65667f24dda6..115516012075 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -12,11 +12,12 @@ use prelude::v1::*; use cell::Cell; use ptr; -use sync::{StaticMutex, Arc}; +use sync::Arc; use sys_common; +use sys_common::mutex::Mutex; pub struct Lazy { - lock: StaticMutex, + lock: Mutex, ptr: Cell<*mut Arc>, init: fn() -> Arc, } @@ -26,23 +27,25 @@ unsafe impl Sync for Lazy {} impl Lazy { pub const fn new(init: fn() -> Arc) -> Lazy { Lazy { - lock: StaticMutex::new(), + lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()), init: init } } pub fn get(&'static self) -> Option> { - let _g = self.lock.lock(); - let ptr = self.ptr.get(); unsafe { - if ptr.is_null() { + self.lock.lock(); + let ptr = self.ptr.get(); + let ret = if ptr.is_null() { Some(self.init()) } else if ptr as usize == 1 { None } else { Some((*ptr).clone()) - } + }; + self.lock.unlock(); + return ret } } @@ -52,10 +55,10 @@ impl Lazy { // the at exit handler). Otherwise we just return the freshly allocated // `Arc`. let registered = sys_common::at_exit(move || { - let g = self.lock.lock(); + self.lock.lock(); let ptr = self.ptr.get(); self.ptr.set(1 as *mut _); - drop(g); + self.lock.unlock(); drop(Box::from_raw(ptr)) }); let ret = (self.init)(); diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 6770eafeac90..016130e99989 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -22,7 +22,7 @@ use rc::Rc; use sync::{Arc, Mutex, RwLock}; use thread::Result; -#[unstable(feature = "panic_handler", issue = "30449")] +#[stable(feature = "panic_hooks", since = "1.10.0")] pub use panicking::{take_hook, set_hook, PanicInfo, Location}; /// diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 3ad330e79fa2..d73e9542d212 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -27,7 +27,7 @@ use fmt; use intrinsics; use mem; use raw; -use sync::StaticRwLock; +use sys_common::rwlock::RWLock; use sync::atomic::{AtomicBool, Ordering}; use sys::stdio::Stderr; use sys_common::backtrace; @@ -69,7 +69,7 @@ enum Hook { Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)), } -static HOOK_LOCK: StaticRwLock = StaticRwLock::new(); +static HOOK_LOCK: RWLock = RWLock::new(); static mut HOOK: Hook = Hook::Default; static FIRST_PANIC: AtomicBool = AtomicBool::new(true); @@ -90,17 +90,17 @@ static FIRST_PANIC: AtomicBool = AtomicBool::new(true); /// # Panics /// /// Panics if called from a panicking thread. -#[unstable(feature = "panic_handler", issue = "30449")] +#[stable(feature = "panic_hooks", since = "1.10.0")] pub fn set_hook(hook: Box) { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } unsafe { - let lock = HOOK_LOCK.write(); + HOOK_LOCK.write(); let old_hook = HOOK; HOOK = Hook::Custom(Box::into_raw(hook)); - drop(lock); + HOOK_LOCK.write_unlock(); if let Hook::Custom(ptr) = old_hook { Box::from_raw(ptr); @@ -115,17 +115,17 @@ pub fn set_hook(hook: Box) { /// # Panics /// /// Panics if called from a panicking thread. -#[unstable(feature = "panic_handler", issue = "30449")] +#[stable(feature = "panic_hooks", since = "1.10.0")] pub fn take_hook() -> Box { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } unsafe { - let lock = HOOK_LOCK.write(); + HOOK_LOCK.write(); let hook = HOOK; HOOK = Hook::Default; - drop(lock); + HOOK_LOCK.write_unlock(); match hook { Hook::Default => Box::new(default_hook), @@ -135,7 +135,7 @@ pub fn take_hook() -> Box { } /// A struct providing information about a panic. -#[unstable(feature = "panic_handler", issue = "30449")] +#[stable(feature = "panic_hooks", since = "1.10.0")] pub struct PanicInfo<'a> { payload: &'a (Any + Send), location: Location<'a>, @@ -145,7 +145,7 @@ impl<'a> PanicInfo<'a> { /// Returns the payload associated with the panic. /// /// This will commonly, but not always, be a `&'static str` or `String`. - #[unstable(feature = "panic_handler", issue = "30449")] + #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn payload(&self) -> &(Any + Send) { self.payload } @@ -155,14 +155,14 @@ impl<'a> PanicInfo<'a> { /// /// This method will currently always return `Some`, but this may change /// in future versions. - #[unstable(feature = "panic_handler", issue = "30449")] + #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn location(&self) -> Option<&Location> { Some(&self.location) } } /// A struct containing information about the location of a panic. -#[unstable(feature = "panic_handler", issue = "30449")] +#[stable(feature = "panic_hooks", since = "1.10.0")] pub struct Location<'a> { file: &'a str, line: u32, @@ -170,13 +170,13 @@ pub struct Location<'a> { impl<'a> Location<'a> { /// Returns the name of the source file from which the panic originated. - #[unstable(feature = "panic_handler", issue = "30449")] + #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn file(&self) -> &str { self.file } /// Returns the line number from which the panic originated. - #[unstable(feature = "panic_handler", issue = "30449")] + #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn line(&self) -> u32 { self.line } @@ -365,11 +365,12 @@ fn rust_panic_with_hook(msg: Box, line: line, }, }; - let _lock = HOOK_LOCK.read(); + HOOK_LOCK.read(); match HOOK { Hook::Default => default_hook(&info), Hook::Custom(ptr) => (*ptr)(&info), } + HOOK_LOCK.read_unlock(); } if panics > 0 { diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 57932f037968..bf4b119a0b66 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -72,6 +72,7 @@ impl WaitTimeoutResult { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub struct Condvar { inner: Box } /// Statically allocated condition variables. @@ -91,6 +92,11 @@ pub struct Condvar { inner: Box } #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `Condvar::new` in a static should \ + suffice")] pub struct StaticCondvar { inner: sys::Condvar, mutex: AtomicUsize, @@ -100,8 +106,15 @@ pub struct StaticCondvar { #[unstable(feature = "static_condvar", reason = "may be merged with Condvar in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `Condvar::new` in a static should \ + suffice")] +#[allow(deprecated)] pub const CONDVAR_INIT: StaticCondvar = StaticCondvar::new(); +#[allow(deprecated)] impl Condvar { /// Creates a new condition variable which is ready to be waited on and /// notified. @@ -228,12 +241,22 @@ impl Default for Condvar { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl Drop for Condvar { fn drop(&mut self) { unsafe { self.inner.inner.destroy() } } } +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `Condvar::new` in a static should \ + suffice")] +#[unstable(feature = "static_condvar", + reason = "may be merged with Condvar in the future", + issue = "27717")] +#[allow(deprecated)] impl StaticCondvar { /// Creates a new condition variable #[unstable(feature = "static_condvar", @@ -392,6 +415,7 @@ impl StaticCondvar { } #[cfg(test)] +#[allow(deprecated)] mod tests { use prelude::v1::*; diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 21008ee3989a..56eb7340c890 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -25,10 +25,13 @@ pub use core::sync::atomic; #[stable(feature = "rust1", since = "1.0.0")] pub use self::barrier::{Barrier, BarrierWaitResult}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub use self::condvar::{Condvar, StaticCondvar, WaitTimeoutResult, CONDVAR_INIT}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub use self::mutex::MUTEX_INIT; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::once::{Once, OnceState, ONCE_INIT}; @@ -37,6 +40,7 @@ pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResul #[stable(feature = "rust1", since = "1.0.0")] pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT}; pub mod mpsc; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 90cc79dad66b..15e69628c7a5 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -113,6 +113,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// *guard += 1; /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never @@ -156,6 +157,11 @@ unsafe impl Sync for Mutex { } #[unstable(feature = "static_mutex", reason = "may be merged with Mutex in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `Mutex::new` in a static should \ + suffice")] pub struct StaticMutex { lock: sys::Mutex, poison: poison::Flag, @@ -168,6 +174,7 @@ pub struct StaticMutex { /// `Deref` and `DerefMut` implementations #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub struct MutexGuard<'a, T: ?Sized + 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). @@ -184,8 +191,15 @@ impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} #[unstable(feature = "static_mutex", reason = "may be merged with Mutex in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `Mutex::new` in a static should \ + suffice")] +#[allow(deprecated)] pub const MUTEX_INIT: StaticMutex = StaticMutex::new(); +#[allow(deprecated)] impl Mutex { /// Creates a new mutex in an unlocked state ready for use. #[stable(feature = "rust1", since = "1.0.0")] @@ -197,6 +211,7 @@ impl Mutex { } } +#[allow(deprecated)] impl Mutex { /// Acquires a mutex, blocking the current thread until it is able to do so. /// @@ -307,6 +322,7 @@ impl Mutex { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl Drop for Mutex { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { @@ -346,6 +362,12 @@ static DUMMY: Dummy = Dummy(UnsafeCell::new(())); #[unstable(feature = "static_mutex", reason = "may be merged with Mutex in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `Mutex::new` in a static should \ + suffice")] +#[allow(deprecated)] impl StaticMutex { /// Creates a new mutex in an unlocked state ready for use. pub const fn new() -> StaticMutex { @@ -391,8 +413,8 @@ impl StaticMutex { } } +#[allow(deprecated)] impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { - unsafe fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { @@ -418,6 +440,7 @@ impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { #[inline] fn drop(&mut self) { @@ -428,15 +451,18 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { } } +#[allow(deprecated)] pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { &guard.__lock.lock } +#[allow(deprecated)] pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.__lock.poison } #[cfg(test)] +#[allow(deprecated)] mod tests { use prelude::v1::*; diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index cfb8ee16cb06..e1e764bd255c 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -66,6 +66,7 @@ use sys_common::rwlock as sys; /// } // write lock is dropped here /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub struct RwLock { inner: Box, data: UnsafeCell, @@ -104,6 +105,11 @@ unsafe impl Sync for RwLock {} #[unstable(feature = "static_rwlock", reason = "may be merged with RwLock in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `RwLock::new` in a static should \ + suffice")] pub struct StaticRwLock { lock: sys::RWLock, poison: poison::Flag, @@ -113,12 +119,19 @@ pub struct StaticRwLock { #[unstable(feature = "static_rwlock", reason = "may be merged with RwLock in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `RwLock::new` in a static should \ + suffice")] +#[allow(deprecated)] pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock::new(); /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, __data: &'a T, @@ -131,6 +144,7 @@ impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {} /// dropped. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { __lock: &'a StaticRwLock, __data: &'a mut T, @@ -140,6 +154,7 @@ pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {} +#[allow(deprecated)] impl RwLock { /// Creates a new instance of an `RwLock` which is unlocked. /// @@ -156,6 +171,7 @@ impl RwLock { } } +#[allow(deprecated)] impl RwLock { /// Locks this rwlock with shared read access, blocking the current thread /// until it can be acquired. @@ -325,6 +341,7 @@ impl RwLock { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl Drop for RwLock { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { @@ -360,6 +377,12 @@ static DUMMY: Dummy = Dummy(UnsafeCell::new(())); #[unstable(feature = "static_rwlock", reason = "may be merged with RwLock in the future", issue = "27717")] +#[rustc_deprecated(since = "1.10.0", + reason = "the lazy-static crate suffices for static sync \ + primitives and eventually this type shouldn't \ + be necessary as `RwLock::new` in a static should \ + suffice")] +#[allow(deprecated)] impl StaticRwLock { /// Creates a new rwlock. pub const fn new() -> StaticRwLock { @@ -434,6 +457,7 @@ impl StaticRwLock { } } +#[allow(deprecated)] impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { @@ -482,6 +506,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { } } +#[allow(deprecated)] impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell) -> LockResult> { @@ -562,10 +587,12 @@ impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> { - fn deref_mut(&mut self) -> &mut T { self.__data + fn deref_mut(&mut self) -> &mut T { + self.__data } } +#[allow(deprecated)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> { fn drop(&mut self) { @@ -573,6 +600,7 @@ impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> { } } +#[allow(deprecated)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { fn drop(&mut self) { @@ -582,6 +610,7 @@ impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { } #[cfg(test)] +#[allow(deprecated)] mod tests { #![allow(deprecated)] // rand diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs index 584175406645..e877391fb8b5 100644 --- a/src/libstd/sys/common/args.rs +++ b/src/libstd/sys/common/args.rs @@ -48,32 +48,36 @@ mod imp { use mem; use ffi::CStr; - use sync::StaticMutex; + use sys_common::mutex::Mutex; static mut GLOBAL_ARGS_PTR: usize = 0; - static LOCK: StaticMutex = StaticMutex::new(); + static LOCK: Mutex = Mutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { let args = (0..argc).map(|i| { CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec() }).collect(); - let _guard = LOCK.lock(); + LOCK.lock(); let ptr = get_global_ptr(); assert!((*ptr).is_none()); (*ptr) = Some(box args); + LOCK.unlock(); } pub unsafe fn cleanup() { - let _guard = LOCK.lock(); + LOCK.lock(); *get_global_ptr() = None; + LOCK.unlock(); } pub fn clone() -> Option>> { - let _guard = LOCK.lock(); unsafe { + LOCK.lock(); let ptr = get_global_ptr(); - (*ptr).as_ref().map(|s| (**s).clone()) + let ret = (*ptr).as_ref().map(|s| (**s).clone()); + LOCK.unlock(); + return ret } } diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs index de93d3d4e509..ca2e70b5003a 100644 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs @@ -18,12 +18,11 @@ /// simple to use it should be used only on iOS devices as the only viable /// option. -use io; use io::prelude::*; +use io; use libc; use mem; -use result::Result::Ok; -use sync::StaticMutex; +use sys::mutex::Mutex; use super::super::printing::print; @@ -37,18 +36,21 @@ pub fn write(w: &mut Write) -> io::Result<()> { // while it doesn't requires lock for work as everything is // local, it still displays much nicer backtraces when a // couple of threads panic simultaneously - static LOCK: StaticMutex = StaticMutex::new(); - let _g = LOCK.lock(); + static LOCK: Mutex = Mutex::new(); + unsafe { + LOCK.lock(); - writeln!(w, "stack backtrace:")?; - // 100 lines should be enough - const SIZE: usize = 100; - let mut buf: [*mut libc::c_void; SIZE] = unsafe { mem::zeroed() }; - let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize}; + writeln!(w, "stack backtrace:")?; + // 100 lines should be enough + const SIZE: usize = 100; + let mut buf: [*mut libc::c_void; SIZE] = mem::zeroed(); + let cnt = backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize; - // skipping the first one as it is write itself - for i in 1..cnt { - print(w, i as isize, buf[i], buf[i])? + // skipping the first one as it is write itself + for i in 1..cnt { + print(w, i as isize, buf[i], buf[i])? + } + LOCK.unlock(); } Ok(()) } diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs index 5f7ad6918cdd..c1b45620ab04 100644 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -12,7 +12,7 @@ use io; use io::prelude::*; use libc; use mem; -use sync::StaticMutex; +use sys_common::mutex::Mutex; use super::super::printing::print; use unwind as uw; @@ -31,24 +31,28 @@ pub fn write(w: &mut Write) -> io::Result<()> { // is semi-reasonable in terms of printing anyway, and we know that all // I/O done here is blocking I/O, not green I/O, so we don't have to // worry about this being a native vs green mutex. - static LOCK: StaticMutex = StaticMutex::new(); - let _g = LOCK.lock(); + static LOCK: Mutex = Mutex::new(); + unsafe { + LOCK.lock(); - writeln!(w, "stack backtrace:")?; + writeln!(w, "stack backtrace:")?; - let mut cx = Context { writer: w, last_error: None, idx: 0 }; - return match unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context as *mut libc::c_void) - } { - uw::_URC_NO_REASON => { - match cx.last_error { - Some(err) => Err(err), - None => Ok(()) + let mut cx = Context { writer: w, last_error: None, idx: 0 }; + let ret = match { + uw::_Unwind_Backtrace(trace_fn, + &mut cx as *mut Context as *mut libc::c_void) + } { + uw::_URC_NO_REASON => { + match cx.last_error { + Some(err) => Err(err), + None => Ok(()) + } } - } - _ => Ok(()), - }; + _ => Ok(()), + }; + LOCK.unlock(); + return ret + } extern fn trace_fn(ctx: *mut uw::_Unwind_Context, arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index a1528458860f..bb90a977433e 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -88,9 +88,7 @@ pub trait OpenOptionsExt { /// } /// let file = options.open("foo.txt"); /// ``` - #[unstable(feature = "expand_open_options", - reason = "recently added", - issue = "30014")] + #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: i32) -> &mut Self; } diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index a74f7ea13b41..b5287cce4843 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -7,7 +7,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "unix_socket", reason = "newly added", issue = "32312")] + +#![stable(feature = "unix_socket", since = "1.10.0")] //! Unix-specific networking functionality @@ -75,6 +76,7 @@ enum AddressKind<'a> { /// An address associated with a Unix socket. #[derive(Clone)] +#[stable(feature = "unix_socket", since = "1.10.0")] pub struct SocketAddr { addr: libc::sockaddr_un, len: libc::socklen_t, @@ -109,6 +111,7 @@ impl SocketAddr { } /// Returns true iff the address is unnamed. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn is_unnamed(&self) -> bool { if let AddressKind::Unnamed = self.address() { true @@ -118,6 +121,7 @@ impl SocketAddr { } /// Returns the contents of this address if it is a `pathname` address. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn as_pathname(&self) -> Option<&Path> { if let AddressKind::Pathname(path) = self.address() { Some(path) @@ -141,6 +145,7 @@ impl SocketAddr { } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self.address() { @@ -168,8 +173,6 @@ impl<'a> fmt::Display for AsciiEscaped<'a> { /// # Examples /// /// ```rust,no_run -/// #![feature(unix_socket)] -/// /// use std::os::unix::net::UnixStream; /// use std::io::prelude::*; /// @@ -179,8 +182,10 @@ impl<'a> fmt::Display for AsciiEscaped<'a> { /// stream.read_to_string(&mut response).unwrap(); /// println!("{}", response); /// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixStream(Socket); +#[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); @@ -197,6 +202,7 @@ impl fmt::Debug for UnixStream { impl UnixStream { /// Connects to the socket named by `path`. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(path: P) -> io::Result { fn inner(path: &Path) -> io::Result { unsafe { @@ -213,6 +219,7 @@ impl UnixStream { /// Creates an unnamed pair of connected sockets. /// /// Returns two `UnixStream`s which are connected to each other. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; Ok((UnixStream(i1), UnixStream(i2))) @@ -224,16 +231,19 @@ impl UnixStream { /// object references. Both handles will read and write the same stream of /// data, and options set on one stream will be propogated to the other /// stream. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } /// Returns the socket address of the local half of this connection. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) } /// Returns the socket address of the remote half of this connection. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } @@ -243,6 +253,7 @@ impl UnixStream { /// If the provided value is `None`, then `read` calls will block /// indefinitely. It is an error to pass the zero `Duration` to this /// method. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) } @@ -252,26 +263,31 @@ impl UnixStream { /// If the provided value is `None`, then `write` calls will block /// indefinitely. It is an error to pass the zero `Duration` to this /// method. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) } /// Returns the read timeout of this socket. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn read_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_RCVTIMEO) } /// Returns the write timeout of this socket. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn write_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_SNDTIMEO) } /// Moves the socket into or out of nonblocking mode. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } /// Returns the value of the `SO_ERROR` option. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() } @@ -281,11 +297,13 @@ impl UnixStream { /// This function will cause all pending and future I/O calls on the /// specified portions to immediately return with an appropriate value /// (see the documentation of `Shutdown`). + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl io::Read for UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) @@ -296,6 +314,7 @@ impl io::Read for UnixStream { } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl<'a> io::Read for &'a UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -306,6 +325,7 @@ impl<'a> io::Read for &'a UnixStream { } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl io::Write for UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { io::Write::write(&mut &*self, buf) @@ -316,6 +336,7 @@ impl io::Write for UnixStream { } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -326,18 +347,21 @@ impl<'a> io::Write for &'a UnixStream { } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixStream { fn as_raw_fd(&self) -> RawFd { *self.0.as_inner() } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixStream { unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(Socket::from_inner(fd)) } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixStream { fn into_raw_fd(self) -> RawFd { self.0.into_inner() @@ -349,8 +373,6 @@ impl IntoRawFd for UnixStream { /// # Examples /// /// ```rust,no_run -/// #![feature(unix_socket)] -/// /// use std::thread; /// use std::os::unix::net::{UnixStream, UnixListener}; /// @@ -377,8 +399,10 @@ impl IntoRawFd for UnixStream { /// // close the listener socket /// drop(listener); /// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixListener(Socket); +#[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); @@ -392,6 +416,7 @@ impl fmt::Debug for UnixListener { impl UnixListener { /// Creates a new `UnixListener` bound to the specified socket. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { fn inner(path: &Path) -> io::Result { unsafe { @@ -412,6 +437,7 @@ impl UnixListener { /// This function will block the calling thread until a new Unix connection /// is established. When established, the corersponding `UnixStream` and /// the remote peer's address will be returned. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as libc::socklen_t; @@ -425,21 +451,25 @@ impl UnixListener { /// The returned `UnixListener` is a reference to the same socket that this /// object references. Both handles can be used to accept incoming /// connections and options set on one listener will affect the other. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } /// Returns the local socket address of this listener. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) } /// Moves the socket into or out of nonblocking mode. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } /// Returns the value of the `SO_ERROR` option. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() } @@ -448,29 +478,34 @@ impl UnixListener { /// /// The iterator will never return `None` and will also not yield the /// peer's `SocketAddr` structure. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn incoming<'a>(&'a self) -> Incoming<'a> { Incoming { listener: self } } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixListener { fn as_raw_fd(&self) -> RawFd { *self.0.as_inner() } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixListener { unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(Socket::from_inner(fd)) } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixListener { fn into_raw_fd(self) -> RawFd { self.0.into_inner() } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; @@ -484,10 +519,12 @@ impl<'a> IntoIterator for &'a UnixListener { /// /// It will never return `None`. #[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] pub struct Incoming<'a> { listener: &'a UnixListener, } +#[stable(feature = "unix_socket", since = "1.10.0")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; @@ -505,8 +542,6 @@ impl<'a> Iterator for Incoming<'a> { /// # Examples /// /// ```rust,no_run -/// #![feature(unix_socket)] -/// /// use std::os::unix::net::UnixDatagram; /// /// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap(); @@ -515,8 +550,10 @@ impl<'a> Iterator for Incoming<'a> { /// let (count, address) = socket.recv_from(&mut buf).unwrap(); /// println!("socket {:?} sent {:?}", address, &buf[..count]); /// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixDatagram(Socket); +#[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixDatagram { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixDatagram"); @@ -533,6 +570,7 @@ impl fmt::Debug for UnixDatagram { impl UnixDatagram { /// Creates a Unix datagram socket bound to the given path. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { fn inner(path: &Path) -> io::Result { unsafe { @@ -548,6 +586,7 @@ impl UnixDatagram { } /// Creates a Unix Datagram socket which is not bound to any address. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn unbound() -> io::Result { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; Ok(UnixDatagram(inner)) @@ -556,6 +595,7 @@ impl UnixDatagram { /// Create an unnamed pair of connected sockets. /// /// Returns two `UnixDatagrams`s which are connected to each other. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; Ok((UnixDatagram(i1), UnixDatagram(i2))) @@ -565,6 +605,7 @@ impl UnixDatagram { /// /// The `send` method may be used to send data to the specified address. /// `recv` and `recv_from` will only receive data from that address. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(&self, path: P) -> io::Result<()> { fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { unsafe { @@ -583,11 +624,13 @@ impl UnixDatagram { /// The returned `UnixListener` is a reference to the same socket that this /// object references. Both handles can be used to accept incoming /// connections and options set on one listener will affect the other. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixDatagram) } /// Returns the address of this socket. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) } @@ -595,6 +638,7 @@ impl UnixDatagram { /// Returns the address of this socket's peer. /// /// The `connect` method will connect the socket to a peer. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } @@ -603,6 +647,7 @@ impl UnixDatagram { /// /// On success, returns the number of bytes read and the address from /// whence the data came. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { let mut count = 0; let addr = SocketAddr::new(|addr, len| { @@ -629,6 +674,7 @@ impl UnixDatagram { /// Receives data from the socket. /// /// On success, returns the number of bytes read. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } @@ -636,6 +682,7 @@ impl UnixDatagram { /// Sends data on the socket to the specified address. /// /// On success, returns the number of bytes written. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { unsafe { @@ -659,6 +706,7 @@ impl UnixDatagram { /// will return an error if the socket has not already been connected. /// /// On success, returns the number of bytes written. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn send(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } @@ -668,6 +716,7 @@ impl UnixDatagram { /// If the provided value is `None`, then `recv` and `recv_from` calls will /// block indefinitely. It is an error to pass the zero `Duration` to this /// method. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) } @@ -677,26 +726,31 @@ impl UnixDatagram { /// If the provided value is `None`, then `send` and `send_to` calls will /// block indefinitely. It is an error to pass the zero `Duration` to this /// method. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) } /// Returns the read timeout of this socket. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn read_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_RCVTIMEO) } /// Returns the write timeout of this socket. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn write_timeout(&self) -> io::Result> { self.0.timeout(libc::SO_SNDTIMEO) } /// Moves the socket into or out of nonblocking mode. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } /// Returns the value of the `SO_ERROR` option. + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() } @@ -706,23 +760,27 @@ impl UnixDatagram { /// This function will cause all pending and future I/O calls on the /// specified portions to immediately return with an appropriate value /// (see the documentation of `Shutdown`). + #[stable(feature = "unix_socket", since = "1.10.0")] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixDatagram { fn as_raw_fd(&self) -> RawFd { *self.0.as_inner() } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixDatagram { unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { UnixDatagram(Socket::from_inner(fd)) } } +#[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixDatagram { fn into_raw_fd(self) -> RawFd { self.0.into_inner() diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0969a59ea433..7f23ae53fcd1 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -100,31 +100,6 @@ impl FileAttr { } } -#[cfg(any(target_os = "ios", target_os = "macos"))] -// FIXME: update SystemTime to store a timespec and don't lose precision -impl FileAttr { - pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timeval { - tv_sec: self.stat.st_mtime, - tv_usec: (self.stat.st_mtime_nsec / 1000) as libc::suseconds_t, - })) - } - - pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timeval { - tv_sec: self.stat.st_atime, - tv_usec: (self.stat.st_atime_nsec / 1000) as libc::suseconds_t, - })) - } - - pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timeval { - tv_sec: self.stat.st_birthtime, - tv_usec: (self.stat.st_birthtime_nsec / 1000) as libc::suseconds_t, - })) - } -} - #[cfg(target_os = "netbsd")] impl FileAttr { pub fn modified(&self) -> io::Result { @@ -149,7 +124,7 @@ impl FileAttr { } } -#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "netbsd")))] +#[cfg(not(target_os = "netbsd"))] impl FileAttr { pub fn modified(&self) -> io::Result { Ok(SystemTime::from(libc::timespec { @@ -167,7 +142,9 @@ impl FileAttr { #[cfg(any(target_os = "bitrig", target_os = "freebsd", - target_os = "openbsd"))] + target_os = "openbsd", + target_os = "macos", + target_os = "ios"))] pub fn created(&self) -> io::Result { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_birthtime as libc::time_t, @@ -177,7 +154,9 @@ impl FileAttr { #[cfg(not(any(target_os = "bitrig", target_os = "freebsd", - target_os = "openbsd")))] + target_os = "openbsd", + target_os = "macos", + target_os = "ios")))] pub fn created(&self) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "creation time is not available on this platform \ diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 94ebbd70ae83..21ce6b19ceb1 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -27,13 +27,13 @@ use path::{self, PathBuf}; use ptr; use slice; use str; -use sync::StaticMutex; +use sys_common::mutex::Mutex; use sys::cvt; use sys::fd; use vec; const TMPBUF_SZ: usize = 128; -static ENV_LOCK: StaticMutex = StaticMutex::new(); +static ENV_LOCK: Mutex = Mutex::new(); /// Returns the platform-specific value of errno #[cfg(not(target_os = "dragonfly"))] @@ -434,10 +434,11 @@ pub unsafe fn environ() -> *mut *const *const c_char { /// Returns a vector of (variable, value) byte-vector pairs for all the /// environment variables of the current process. pub fn env() -> Env { - let _g = ENV_LOCK.lock(); - return unsafe { + unsafe { + ENV_LOCK.lock(); let mut environ = *environ(); if environ == ptr::null() { + ENV_LOCK.unlock(); panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error()); } @@ -448,8 +449,13 @@ pub fn env() -> Env { } environ = environ.offset(1); } - Env { iter: result.into_iter(), _dont_send_or_sync_me: ptr::null_mut() } - }; + let ret = Env { + iter: result.into_iter(), + _dont_send_or_sync_me: ptr::null_mut(), + }; + ENV_LOCK.unlock(); + return ret + } fn parse(input: &[u8]) -> Option<(OsString, OsString)> { // Strategy (copied from glibc): Variable name and value are separated @@ -471,32 +477,40 @@ pub fn getenv(k: &OsStr) -> io::Result> { // environment variables with a nul byte can't be set, so their value is // always None as well let k = CString::new(k.as_bytes())?; - let _g = ENV_LOCK.lock(); - Ok(unsafe { + unsafe { + ENV_LOCK.lock(); let s = libc::getenv(k.as_ptr()) as *const _; - if s.is_null() { + let ret = if s.is_null() { None } else { Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) - } - }) + }; + ENV_LOCK.unlock(); + return Ok(ret) + } } pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let k = CString::new(k.as_bytes())?; let v = CString::new(v.as_bytes())?; - let _g = ENV_LOCK.lock(); - cvt(unsafe { - libc::setenv(k.as_ptr(), v.as_ptr(), 1) - }).map(|_| ()) + + unsafe { + ENV_LOCK.lock(); + let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()); + ENV_LOCK.unlock(); + return ret + } } pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; - let _g = ENV_LOCK.lock(); - cvt(unsafe { - libc::unsetenv(nbuf.as_ptr()) - }).map(|_| ()) + + unsafe { + ENV_LOCK.lock(); + let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()); + ENV_LOCK.unlock(); + return ret + } } pub fn page_size() -> usize { diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index cc7abe25e35e..68eebba9e7b9 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -8,37 +8,129 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use cmp::Ordering; +use time::Duration; +use libc; + pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; const NSEC_PER_SEC: u64 = 1_000_000_000; +#[derive(Copy, Clone)] +struct Timespec { + t: libc::timespec, +} + +impl Timespec { + fn sub_timespec(&self, other: &Timespec) -> Result { + if self >= other { + Ok(if self.t.tv_nsec >= other.t.tv_nsec { + Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, + (self.t.tv_nsec - other.t.tv_nsec) as u32) + } else { + Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, + self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - + other.t.tv_nsec as u32) + }) + } else { + match other.sub_timespec(self) { + Ok(d) => Err(d), + Err(d) => Ok(d), + } + } + } + + fn add_duration(&self, other: &Duration) -> Timespec { + let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); + let mut secs = secs.expect("overflow when adding duration to time"); + + // Nano calculations can't overflow because nanos are <1B which fit + // in a u32. + let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; + if nsec >= NSEC_PER_SEC as u32 { + nsec -= NSEC_PER_SEC as u32; + secs = secs.checked_add(1).expect("overflow when adding \ + duration to time"); + } + Timespec { + t: libc::timespec { + tv_sec: secs as libc::time_t, + tv_nsec: nsec as libc::c_long, + }, + } + } + + fn sub_duration(&self, other: &Duration) -> Timespec { + let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); + let mut secs = secs.expect("overflow when subtracting duration \ + from time"); + + // Similar to above, nanos can't overflow. + let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; + if nsec < 0 { + nsec += NSEC_PER_SEC as i32; + secs = secs.checked_sub(1).expect("overflow when subtracting \ + duration from time"); + } + Timespec { + t: libc::timespec { + tv_sec: secs as libc::time_t, + tv_nsec: nsec as libc::c_long, + }, + } + } +} + +impl PartialEq for Timespec { + fn eq(&self, other: &Timespec) -> bool { + self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec + } +} + +impl Eq for Timespec {} + +impl PartialOrd for Timespec { + fn partial_cmp(&self, other: &Timespec) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Timespec { + fn cmp(&self, other: &Timespec) -> Ordering { + let me = (self.t.tv_sec, self.t.tv_nsec); + let other = (other.t.tv_sec, other.t.tv_nsec); + me.cmp(&other) + } +} + #[cfg(any(target_os = "macos", target_os = "ios"))] mod inner { - use cmp::Ordering; use fmt; use libc; - use super::NSEC_PER_SEC; use sync::Once; use sys::cvt; use sys_common::mul_div_u64; use time::Duration; - const USEC_PER_SEC: u64 = NSEC_PER_SEC / 1000; + use super::NSEC_PER_SEC; + use super::Timespec; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct Instant { t: u64 } - #[derive(Copy, Clone)] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct SystemTime { - t: libc::timeval, + t: Timespec, } pub const UNIX_EPOCH: SystemTime = SystemTime { - t: libc::timeval { - tv_sec: 0, - tv_usec: 0, + t: Timespec { + t: libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, }, }; @@ -72,113 +164,50 @@ mod inner { impl SystemTime { pub fn now() -> SystemTime { - let mut s = SystemTime { - t: libc::timeval { - tv_sec: 0, - tv_usec: 0, - }, + let mut s = libc::timeval { + tv_sec: 0, + tv_usec: 0, }; cvt(unsafe { - libc::gettimeofday(&mut s.t, 0 as *mut _) + libc::gettimeofday(&mut s, 0 as *mut _) }).unwrap(); - return s + return SystemTime::from(s) } pub fn sub_time(&self, other: &SystemTime) -> Result { - if self >= other { - Ok(if self.t.tv_usec >= other.t.tv_usec { - Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, - ((self.t.tv_usec - - other.t.tv_usec) as u32) * 1000) - } else { - Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, - (self.t.tv_usec as u32 + (USEC_PER_SEC as u32) - - other.t.tv_usec as u32) * 1000) - }) - } else { - match other.sub_time(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } + self.t.sub_timespec(&other.t) } pub fn add_duration(&self, other: &Duration) -> SystemTime { - let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); - let mut secs = secs.expect("overflow when adding duration to time"); - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut usec = (other.subsec_nanos() / 1000) + self.t.tv_usec as u32; - if usec >= USEC_PER_SEC as u32 { - usec -= USEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); - } - SystemTime { - t: libc::timeval { - tv_sec: secs as libc::time_t, - tv_usec: usec as libc::suseconds_t, - }, - } + SystemTime { t: self.t.add_duration(other) } } pub fn sub_duration(&self, other: &Duration) -> SystemTime { - let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); - let mut secs = secs.expect("overflow when subtracting duration \ - from time"); - - // Similar to above, nanos can't overflow. - let mut usec = self.t.tv_usec as i32 - - (other.subsec_nanos() / 1000) as i32; - if usec < 0 { - usec += USEC_PER_SEC as i32; - secs = secs.checked_sub(1).expect("overflow when subtracting \ - duration from time"); - } - SystemTime { - t: libc::timeval { - tv_sec: secs as libc::time_t, - tv_usec: usec as libc::suseconds_t, - }, - } + SystemTime { t: self.t.sub_duration(other) } } } impl From for SystemTime { fn from(t: libc::timeval) -> SystemTime { - SystemTime { t: t } - } - } - - impl PartialEq for SystemTime { - fn eq(&self, other: &SystemTime) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_usec == other.t.tv_usec - } - } - - impl Eq for SystemTime {} - - impl PartialOrd for SystemTime { - fn partial_cmp(&self, other: &SystemTime) -> Option { - Some(self.cmp(other)) + SystemTime::from(libc::timespec { + tv_sec: t.tv_sec, + tv_nsec: (t.tv_usec * 1000) as libc::c_long, + }) } } - impl Ord for SystemTime { - fn cmp(&self, other: &SystemTime) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_usec); - let other = (other.t.tv_sec, other.t.tv_usec); - me.cmp(&other) + impl From for SystemTime { + fn from(t: libc::timespec) -> SystemTime { + SystemTime { t: Timespec { t: t } } } } impl fmt::Debug for SystemTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SystemTime") - .field("tv_sec", &self.t.tv_sec) - .field("tv_usec", &self.t.tv_usec) + .field("tv_sec", &self.t.t.tv_sec) + .field("tv_nsec", &self.t.t.tv_nsec) .finish() } } @@ -209,17 +238,12 @@ mod inner { #[cfg(not(any(target_os = "macos", target_os = "ios")))] mod inner { - use cmp::Ordering; use fmt; use libc; - use super::NSEC_PER_SEC; use sys::cvt; use time::Duration; - #[derive(Copy, Clone)] - struct Timespec { - t: libc::timespec, - } + use super::Timespec; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Instant { @@ -242,7 +266,7 @@ mod inner { impl Instant { pub fn now() -> Instant { - Instant { t: Timespec::now(libc::CLOCK_MONOTONIC) } + Instant { t: now(libc::CLOCK_MONOTONIC) } } pub fn sub_instant(&self, other: &Instant) -> Duration { @@ -271,7 +295,7 @@ mod inner { impl SystemTime { pub fn now() -> SystemTime { - SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } + SystemTime { t: now(libc::CLOCK_REALTIME) } } pub fn sub_time(&self, other: &SystemTime) @@ -308,98 +332,16 @@ mod inner { #[cfg(target_os = "dragonfly")] pub type clock_t = libc::c_ulong; - impl Timespec { - pub fn now(clock: clock_t) -> Timespec { - let mut t = Timespec { - t: libc::timespec { - tv_sec: 0, - tv_nsec: 0, - } - }; - cvt(unsafe { - libc::clock_gettime(clock, &mut t.t) - }).unwrap(); - t - } - - fn sub_timespec(&self, other: &Timespec) -> Result { - if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32) - } else { - Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - - other.t.tv_nsec as u32) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn add_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); - let mut secs = secs.expect("overflow when adding duration to time"); - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); - } - Timespec { - t: libc::timespec { - tv_sec: secs as libc::time_t, - tv_nsec: nsec as libc::c_long, - }, - } - } - - fn sub_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); - let mut secs = secs.expect("overflow when subtracting duration \ - from time"); - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1).expect("overflow when subtracting \ - duration from time"); - } - Timespec { - t: libc::timespec { - tv_sec: secs as libc::time_t, - tv_nsec: nsec as libc::c_long, - }, + fn now(clock: clock_t) -> Timespec { + let mut t = Timespec { + t: libc::timespec { + tv_sec: 0, + tv_nsec: 0, } - } - } - - impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } - } - - impl Eq for Timespec {} - - impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } - } - - impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } + }; + cvt(unsafe { + libc::clock_gettime(clock, &mut t.t) + }).unwrap(); + t } } diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index d378a6853f3c..4388a0bdff2c 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -19,9 +19,7 @@ use sys; use sys_common::{AsInnerMut, AsInner}; /// Windows-specific extensions to `OpenOptions` -#[unstable(feature = "open_options_ext", - reason = "may require more thought/methods", - issue = "27720")] +#[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` /// with the specified value. @@ -34,7 +32,6 @@ pub trait OpenOptionsExt { /// # Examples /// /// ```no_run - /// #![feature(open_options_ext)] /// use std::fs::OpenOptions; /// use std::os::windows::fs::OpenOptionsExt; /// @@ -42,6 +39,7 @@ pub trait OpenOptionsExt { /// // to call `stat()` on the file /// let file = OpenOptions::new().access_mode(0).open("foo.txt"); /// ``` + #[stable(feature = "open_options_ext", since = "1.10.0")] fn access_mode(&mut self, access: u32) -> &mut Self; /// Overrides the `dwShareMode` argument to the call to `CreateFile` with @@ -55,7 +53,6 @@ pub trait OpenOptionsExt { /// # Examples /// /// ```no_run - /// #![feature(open_options_ext)] /// use std::fs::OpenOptions; /// use std::os::windows::fs::OpenOptionsExt; /// @@ -65,6 +62,7 @@ pub trait OpenOptionsExt { /// .share_mode(0) /// .open("foo.txt"); /// ``` + #[stable(feature = "open_options_ext", since = "1.10.0")] fn share_mode(&mut self, val: u32) -> &mut Self; /// Sets extra flags for the `dwFileFlags` argument to the call to @@ -88,9 +86,7 @@ pub trait OpenOptionsExt { /// } /// let file = options.open("foo.txt"); /// ``` - #[unstable(feature = "expand_open_options", - reason = "recently added", - issue = "30014")] + #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: u32) -> &mut Self; /// Sets the `dwFileAttributes` argument to the call to `CreateFile2` to @@ -111,7 +107,6 @@ pub trait OpenOptionsExt { /// # Examples /// /// ```rust,ignore - /// #![feature(open_options_ext)] /// extern crate winapi; /// use std::fs::OpenOptions; /// use std::os::windows::fs::OpenOptionsExt; @@ -120,17 +115,17 @@ pub trait OpenOptionsExt { /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN) /// .open("foo.txt"); /// ``` + #[stable(feature = "open_options_ext", since = "1.10.0")] fn attributes(&mut self, val: u32) -> &mut Self; /// Sets the `dwSecurityQosFlags` argument to the call to `CreateFile2` to /// the specified value (or combines it with `custom_flags` and `attributes` /// to set the `dwFlagsAndAttributes` for `CreateFile`). + #[stable(feature = "open_options_ext", since = "1.10.0")] fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions; } -#[unstable(feature = "open_options_ext", - reason = "may require more thought/methods", - issue = "27720")] +#[stable(feature = "open_options_ext", since = "1.10.0")] impl OpenOptionsExt for OpenOptions { fn access_mode(&mut self, access: u32) -> &mut OpenOptions { self.as_inner_mut().access_mode(access); self diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index a0ad866c69d4..3ca75cf36437 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -24,7 +24,7 @@ use mem; use os::windows::ffi::OsStrExt; use path::Path; use ptr; -use sync::StaticMutex; +use sys::mutex::Mutex; use sys::c; use sys::fs::{OpenOptions, File}; use sys::handle::Handle; @@ -75,6 +75,10 @@ pub struct StdioPipes { pub stderr: Option, } +struct DropGuard<'a> { + lock: &'a Mutex, +} + impl Command { pub fn new(program: &OsStr) -> Command { Command { @@ -173,8 +177,8 @@ impl Command { // // For more information, msdn also has an article about this race: // http://support.microsoft.com/kb/315939 - static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new(); - let _lock = CREATE_PROCESS_LOCK.lock(); + static CREATE_PROCESS_LOCK: Mutex = Mutex::new(); + let _guard = DropGuard::new(&CREATE_PROCESS_LOCK); let mut pipes = StdioPipes { stdin: None, @@ -224,6 +228,23 @@ impl fmt::Debug for Command { } } +impl<'a> DropGuard<'a> { + fn new(lock: &'a Mutex) -> DropGuard<'a> { + unsafe { + lock.lock(); + DropGuard { lock: lock } + } + } +} + +impl<'a> Drop for DropGuard<'a> { + fn drop(&mut self) { + unsafe { + self.lock.unlock(); + } + } +} + impl Stdio { fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option) -> io::Result { From 85c314f430da84d20aeb5a5ddb1087c34c72861a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 24 May 2016 15:08:07 -0400 Subject: [PATCH 116/179] correct typo in comment --- src/librustc_trans/partitioning.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index d2ddbccee8b4..2ded643ef4fd 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -228,7 +228,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - // always ensure we have at least one CGO; otherwise, if we have a + // always ensure we have at least one CGU; otherwise, if we have a // crate with just types (for example), we could wind up with no CGU if codegen_units.is_empty() { let codegen_unit_name = InternedString::new(FALLBACK_CODEGEN_UNIT); From a01c2570e34ba65e0355e43897647bbfdcc06d08 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 117/179] Apply visit_path to import prefixes by default --- src/librustc/hir/intravisit.rs | 15 ++++----------- src/librustc_incremental/calculate_svh.rs | 4 ---- src/libsyntax/visit.rs | 15 ++++----------- 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9c61271fbfbd..4de876adc1fa 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -280,12 +280,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_path(path, item.id); } ViewPathList(ref prefix, ref list) => { - if !list.is_empty() { - for item in list { - visitor.visit_path_list_item(prefix, item) - } - } else { - visitor.visit_path(prefix, item.id); + visitor.visit_path(prefix, item.id); + for item in list { + visitor.visit_path_list_item(prefix, item) } } } @@ -419,12 +416,8 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { } pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, - prefix: &'v Path, + _prefix: &'v Path, item: &'v PathListItem) { - for segment in &prefix.segments { - visitor.visit_path_segment(prefix.span, segment); - } - walk_opt_name(visitor, item.span, item.node.name()); walk_opt_name(visitor, item.span, item.node.rename()); } diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index 3dd1b6eb205d..a039467c8afc 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -401,10 +401,6 @@ mod svh_visitor { SawPath.hash(self.st); visit::walk_path(self, path) } - fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) { - SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item) - } - fn visit_block(&mut self, b: &'a Block) { SawBlock.hash(self.st); visit::walk_block(self, b) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3bd300a8e8c2..40b2e0bc47e2 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -254,12 +254,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_path(path, item.id); } ViewPathList(ref prefix, ref list) => { - if !list.is_empty() { - for item in list { - visitor.visit_path_list_item(prefix, item) - } - } else { - visitor.visit_path(prefix, item.id); + visitor.visit_path(prefix, item.id); + for item in list { + visitor.visit_path_list_item(prefix, item) } } } @@ -389,12 +386,8 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { } } -pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, prefix: &'v Path, +pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem) { - for segment in &prefix.segments { - visitor.visit_path_segment(prefix.span, segment); - } - walk_opt_ident(visitor, item.span, item.node.name()); walk_opt_ident(visitor, item.span, item.node.rename()); } From cd8e828e94734ec11a24b1415996c214b9456ced Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 24 May 2016 14:37:11 +0300 Subject: [PATCH 118/179] refactor autoderef to avoid registering obligations Refactor `FnCtxt::autoderef` to use an external iterator and to not register any obligation from the main autoderef loop, but rather to register them after (and if) the loop successfully completes. Fixes #24819 Fixes #25801 Fixes #27631 Fixes #31258 Fixes #31964 Fixes #32320 Fixes #33515 Fixes #33755 --- src/librustc/traits/mod.rs | 2 +- src/librustc/ty/adjustment.rs | 3 +- src/librustc_typeck/check/autoderef.rs | 210 ++++++++++++++ src/librustc_typeck/check/callee.rs | 18 +- src/librustc_typeck/check/coercion.rs | 32 +-- src/librustc_typeck/check/method/confirm.rs | 100 +++---- src/librustc_typeck/check/method/probe.rs | 35 ++- src/librustc_typeck/check/method/suggest.rs | 63 ++--- src/librustc_typeck/check/mod.rs | 257 ++++-------------- src/test/compile-fail/E0055.rs | 1 - ...rrowck-borrow-overloaded-auto-deref-mut.rs | 2 +- src/test/compile-fail/issue-24819.rs | 21 ++ 12 files changed, 388 insertions(+), 356 deletions(-) create mode 100644 src/librustc_typeck/check/autoderef.rs create mode 100644 src/test/compile-fail/issue-24819.rs diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c5db2a8a7807..c177ec4dbede 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -31,7 +31,7 @@ pub use self::coherence::overlapping_impls; pub use self::coherence::OrphanCheckErr; pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation}; pub use self::project::{MismatchedProjectionTypes, ProjectionMode}; -pub use self::project::{normalize, Normalized}; +pub use self::project::{normalize, normalize_projection_type, Normalized}; pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 71e49031347b..60f2ca6f4d9b 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -235,8 +235,9 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { None => { span_bug!( expr_span, - "the {}th autoderef failed: {}", + "the {}th autoderef for {} failed: {}", autoderef, + expr_id, adjusted_ty); } } diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs new file mode 100644 index 000000000000..9e2b7cd03465 --- /dev/null +++ b/src/librustc_typeck/check/autoderef.rs @@ -0,0 +1,210 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use astconv::AstConv; + +use super::FnCtxt; + +use rustc::traits; +use rustc::ty::{self, Ty, TraitRef}; +use rustc::ty::{ToPredicate, TypeFoldable}; +use rustc::ty::{MethodCall, MethodCallee}; +use rustc::ty::subst::Substs; +use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; +use rustc::hir; + +use syntax::codemap::Span; +use syntax::parse::token; + +#[derive(Copy, Clone, Debug)] +enum AutoderefKind { + Builtin, + Overloaded +} + +pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { + fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + steps: Vec<(Ty<'tcx>, AutoderefKind)>, + cur_ty: Ty<'tcx>, + obligations: Vec>, + at_start: bool, + span: Span +} + +impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { + type Item = (Ty<'tcx>, usize); + + fn next(&mut self) -> Option { + let tcx = self.fcx.tcx; + + debug!("autoderef: steps={:?}, cur_ty={:?}", + self.steps, self.cur_ty); + if self.at_start { + self.at_start = false; + debug!("autoderef stage #0 is {:?}", self.cur_ty); + return Some((self.cur_ty, 0)); + } + + if self.steps.len() == tcx.sess.recursion_limit.get() { + // We've reached the recursion limit, error gracefully. + span_err!(tcx.sess, self.span, E0055, + "reached the recursion limit while auto-dereferencing {:?}", + self.cur_ty); + return None; + } + + if self.cur_ty.is_ty_var() { + return None; + } + + // Otherwise, deref if type is derefable: + let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(false, NoPreference) { + (AutoderefKind::Builtin, mt.ty) + } else { + match self.overloaded_deref_ty(self.cur_ty) { + Some(ty) => (AutoderefKind::Overloaded, ty), + _ => return None + } + }; + + if new_ty.references_error() { + return None; + } + + self.steps.push((self.cur_ty, kind)); + debug!("autoderef stage #{:?} is {:?} from {:?}", self.steps.len(), + new_ty, (self.cur_ty, kind)); + self.cur_ty = new_ty; + + Some((self.cur_ty, self.steps.len())) + } +} + +impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { + fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { + debug!("overloaded_deref_ty({:?})", ty); + + let tcx = self.fcx.tcx(); + + // + let trait_ref = TraitRef { + def_id: match tcx.lang_items.deref_trait() { + Some(f) => f, + None => return None + }, + substs: tcx.mk_substs(Substs::new_trait(vec![], vec![], self.cur_ty)) + }; + + let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + + let mut selcx = traits::SelectionContext::new(self.fcx); + let obligation = traits::Obligation::new(cause.clone(), trait_ref.to_predicate()); + if !selcx.evaluate_obligation(&obligation) { + debug!("overloaded_deref_ty: cannot match obligation"); + return None; + } + + let normalized = traits::normalize_projection_type( + &mut selcx, + ty::ProjectionTy { + trait_ref: trait_ref, + item_name: token::intern("Target") + }, + cause, + 0 + ); + + debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized); + self.obligations.extend(normalized.obligations); + + Some(self.fcx.resolve_type_vars_if_possible(&normalized.value)) + } + + pub fn unambiguous_final_ty(&self) -> Ty<'tcx> { + self.fcx.structurally_resolved_type(self.span, self.cur_ty) + } + + pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) + where I: IntoIterator + { + let methods : Vec<_> = self.steps.iter().map(|&(ty, kind)| { + if let AutoderefKind::Overloaded = kind { + self.fcx.try_overloaded_deref(self.span, None, ty, pref) + } else { + None + } + }).collect(); + + debug!("finalize({:?}) - {:?},{:?}", pref, methods, self.obligations); + + for expr in exprs { + debug!("finalize - finalizing #{} - {:?}", expr.id, expr); + for (n, method) in methods.iter().enumerate() { + if let &Some(method) = method { + let method_call = MethodCall::autoderef(expr.id, n as u32); + self.fcx.tables.borrow_mut().method_map.insert(method_call, method); + } + } + } + + for obligation in self.obligations { + self.fcx.register_predicate(obligation); + } + } +} + +impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { + pub fn autoderef(&'a self, + span: Span, + base_ty: Ty<'tcx>) + -> Autoderef<'a, 'gcx, 'tcx> + { + Autoderef { + fcx: self, + steps: vec![], + cur_ty: self.resolve_type_vars_if_possible(&base_ty), + obligations: vec![], + at_start: true, + span: span + } + } + + pub fn try_overloaded_deref(&self, + span: Span, + base_expr: Option<&hir::Expr>, + base_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option> + { + debug!("try_overloaded_deref({:?},{:?},{:?},{:?})", + span, base_expr, base_ty, lvalue_pref); + // Try DerefMut first, if preferred. + let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) { + (PreferMutLvalue, Some(trait_did)) => { + self.lookup_method_in_trait(span, base_expr, + token::intern("deref_mut"), trait_did, + base_ty, None) + } + _ => None + }; + + // Otherwise, fall back to Deref. + let method = match (method, self.tcx.lang_items.deref_trait()) { + (None, Some(trait_did)) => { + self.lookup_method_in_trait(span, base_expr, + token::intern("deref"), trait_did, + base_ty, None) + } + (method, _) => method + }; + + method + } +} diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 7493ca70f556..417b2fafecfd 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -9,7 +9,7 @@ // except according to those terms. use super::{DeferredCallResolution, Expectation, FnCtxt, - TupleArgumentsFlag, UnresolvedTypeAction}; + TupleArgumentsFlag}; use CrateCtxt; use middle::cstore::LOCAL_CRATE; @@ -72,15 +72,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { self.check_expr(callee_expr); let original_callee_ty = self.expr_ty(callee_expr); - let (callee_ty, _, result) = - self.autoderef(callee_expr.span, - original_callee_ty, - || Some(callee_expr), - UnresolvedTypeAction::Error, - LvaluePreference::NoPreference, - |adj_ty, idx| { - self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) - }); + + let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty); + let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| { + self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) + }).next(); + let callee_ty = autoderef.unambiguous_final_ty(); + autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr)); match result { None => { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 4861ab15e2c0..2225fd588b1c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,7 +60,7 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use check::{FnCtxt, UnresolvedTypeAction}; +use check::{FnCtxt}; use rustc::hir; use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace}; @@ -220,7 +220,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { -> CoerceResult<'tcx> // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, - I: IntoIterator { + I: IntoIterator + { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); @@ -240,18 +241,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let span = self.origin.span(); - let lvalue_pref = LvaluePreference::from_mutbl(mt_b.mutbl); let mut first_error = None; let mut r_borrow_var = None; - let (_, autoderefs, success) = self.autoderef(span, a, exprs, - UnresolvedTypeAction::Ignore, - lvalue_pref, - |referent_ty, autoderef| - { - if autoderef == 0 { + let mut autoderef = self.autoderef(span, a); + let mut success = None; + + for (referent_ty, autoderefs) in autoderef.by_ref() { + if autoderefs == 0 { // Don't let this pass, otherwise it would cause // &T to autoref to &&T. - return None; + continue } // At this point, we have deref'd `a` to `referent_ty`. So @@ -326,7 +325,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // and let regionck figure it out. let r = if !self.use_lub { r_b // [2] above - } else if autoderef == 1 { + } else if autoderefs == 1 { r_a // [3] above } else { if r_borrow_var.is_none() { // create var lazilly, at most once @@ -341,23 +340,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mt_b.mutbl // [1] above }); match self.unify(derefd_ty_a, b) { - Ok(ty) => Some(ty), + Ok(ty) => { success = Some((ty, autoderefs)); break }, Err(err) => { if first_error.is_none() { first_error = Some(err); } - None } } - }); + } // Extract type or return an error. We return the first error // we got, which should be from relating the "base" type // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let ty = match success { - Some(ty) => ty, + let (ty, autoderefs) = match success { + Some(d) => d, None => { let err = first_error.expect("coerce_borrowed_pointer had no error"); debug!("coerce_borrowed_pointer: failed with err = {:?}", err); @@ -365,6 +363,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; + autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs()); + // Now apply the autoref. We have to extract the region out of // the final ref type we got. if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6faf6f415c26..683a67ff07cf 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -11,11 +11,10 @@ use super::probe; use check::{FnCtxt, callee}; -use check::UnresolvedTypeAction; use hir::def_id::DefId; use rustc::ty::subst::{self}; use rustc::traits; -use rustc::ty::{self, NoPreference, PreferMutLvalue, Ty}; +use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk, TypeOrigin}; @@ -133,10 +132,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { ty: fty, substs: all_substs }; - // If this is an `&mut self` method, bias the receiver - // expression towards mutability (this will switch - // e.g. `Deref` to `DerefMut` in overloaded derefs and so on). - self.fixup_derefs_on_method_receiver_if_necessary(&callee); + + if let Some(hir::MutMutable) = pick.autoref { + self.convert_lvalue_derefs_to_mutable(); + } callee } @@ -164,22 +163,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { (None, None) }; - // Commit the autoderefs by calling `autoderef again, but this + // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various tables. - let (autoderefd_ty, n, result) = self.autoderef(self.span, - unadjusted_self_ty, - || Some(self.self_expr), - UnresolvedTypeAction::Error, - NoPreference, - |_, n| { - if n == pick.autoderefs { - Some(()) - } else { - None - } - }); + let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); + let (autoderefd_ty, n) = autoderef.nth(pick.autoderefs).unwrap(); assert_eq!(n, pick.autoderefs); - assert_eq!(result, Some(())); + + autoderef.unambiguous_final_ty(); + autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr)); // Write out the final adjustment. self.write_adjustment(self.self_expr.id, AdjustDerefRef(AutoDerefRef { @@ -293,27 +284,21 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // yield an object-type (e.g., `&Object` or `Box` // etc). - let (_, _, result) = self.fcx.autoderef(self.span, - self_ty, - || None, - UnresolvedTypeAction::Error, - NoPreference, - |ty, _| { - match ty.sty { - ty::TyTrait(ref data) => Some(closure(self, ty, &data)), - _ => None, - } - }); - - match result { - Some(r) => r, - None => { + // FIXME: this feels, like, super dubious + self.fcx.autoderef(self.span, self_ty) + .filter_map(|(ty, _)| { + match ty.sty { + ty::TyTrait(ref data) => Some(closure(self, ty, &data)), + _ => None, + } + }) + .next() + .unwrap_or_else(|| { span_bug!( self.span, "self-type `{}` for ObjectPick never dereferenced to an object", self_ty) - } - } + }) } fn instantiate_method_substs(&mut self, @@ -463,24 +448,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // RECONCILIATION - /// When we select a method with an `&mut self` receiver, we have to go convert any + /// When we select a method with a mutable autoref, we have to go convert any /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut` /// respectively. - fn fixup_derefs_on_method_receiver_if_necessary(&self, - method_callee: &ty::MethodCallee) { - let sig = match method_callee.ty.sty { - ty::TyFnDef(_, _, ref f) => f.sig.clone(), - _ => return, - }; - - match sig.0.inputs[0].sty { - ty::TyRef(_, ty::TypeAndMut { - ty: _, - mutbl: hir::MutMutable, - }) => {} - _ => return, - } - + fn convert_lvalue_derefs_to_mutable(&self) { // Gather up expressions we want to munge. let mut exprs = Vec::new(); exprs.push(self.self_expr); @@ -495,8 +466,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } } - debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={:?}", - exprs); + debug!("convert_lvalue_derefs_to_mutable: exprs={:?}", exprs); // Fix up autoderefs and derefs. for (i, &expr) in exprs.iter().rev().enumerate() { @@ -509,23 +479,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { Some(_) | None => 0, }; - debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={:?} \ - autoderef_count={}", + debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \ + autoderef_count={}", i, expr, autoderef_count); if autoderef_count > 0 { - self.autoderef(expr.span, - self.expr_ty(expr), - || Some(expr), - UnresolvedTypeAction::Error, - PreferMutLvalue, - |_, autoderefs| { - if autoderefs == autoderef_count + 1 { - Some(()) - } else { - None - } + let mut autoderef = self.autoderef(expr.span, self.expr_ty(expr)); + autoderef.nth(autoderef_count).unwrap_or_else(|| { + span_bug!(expr.span, "expr was deref-able {} times but now isn't?", + autoderef_count); }); + autoderef.finalize(PreferMutLvalue, Some(expr)); } // Don't retry the first one or we might infinite loop! diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 08c041225171..0bb078dfbcba 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -13,13 +13,13 @@ use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; use super::suggest; -use check::{FnCtxt, UnresolvedTypeAction}; +use check::{FnCtxt}; use hir::def_id::DefId; use hir::def::Def; use rustc::ty::subst; use rustc::ty::subst::Subst; use rustc::traits; -use rustc::ty::{self, NoPreference, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; +use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::infer::{InferOk, TypeOrigin}; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; @@ -208,25 +208,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) - -> Option>> { - let mut steps = Vec::new(); - - let (final_ty, dereferences, _) = self.autoderef(span, - self_ty, - || None, - UnresolvedTypeAction::Error, - NoPreference, - |t, d| { - steps.push(CandidateStep { - self_ty: t, - autoderefs: d, - unsize: false - }); - None::<()> // keep iterating until we can't anymore - }); + -> Option>> + { + // FIXME: we don't need to create the entire steps in one pass + let mut autoderef = self.autoderef(span, self_ty); + let mut steps: Vec<_> = autoderef.by_ref().map(|(ty, d)| CandidateStep { + self_ty: ty, + autoderefs: d, + unsize: false + }).collect(); + + let final_ty = autoderef.unambiguous_final_ty(); match final_ty.sty { ty::TyArray(elem_ty, _) => { + let dereferences = steps.len() - 1; + steps.push(CandidateStep { self_ty: self.tcx.mk_slice(elem_ty), autoderefs: dereferences, @@ -237,6 +234,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => (), } + debug!("create_steps: steps={:?}", steps); + Some(steps) } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2cd60d20251f..6f0d2bc0ca5e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -13,7 +13,7 @@ use CrateCtxt; -use check::{self, FnCtxt, UnresolvedTypeAction}; +use check::{FnCtxt}; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; use middle::cstore; @@ -21,7 +21,6 @@ use hir::def::Def; use hir::def_id::DefId; use middle::lang_items::FnOnceTraitLangItem; use rustc::ty::subst::Substs; -use rustc::ty::LvaluePreference; use rustc::traits::{Obligation, SelectionContext}; use util::nodemap::{FnvHashSet}; @@ -48,42 +47,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true, // If it's not a simple function, look for things which implement FnOnce _ => { - if let Ok(fn_once_trait_did) = - tcx.lang_items.require(FnOnceTraitLangItem) { - let (_, _, opt_is_fn) = self.autoderef(span, - ty, - || None, - UnresolvedTypeAction::Ignore, - LvaluePreference::NoPreference, - |ty, _| { - self.probe(|_| { - let fn_once_substs = - Substs::new_trait(vec![self.next_ty_var()], vec![], ty); - let trait_ref = - ty::TraitRef::new(fn_once_trait_did, - tcx.mk_substs(fn_once_substs)); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = Obligation::misc(span, - self.body_id, - poly_trait_ref - .to_predicate()); - let mut selcx = SelectionContext::new(self); - - if selcx.evaluate_obligation(&obligation) { - Some(()) - } else { - None - } - }) - }); + let fn_once = match tcx.lang_items.require(FnOnceTraitLangItem) { + Ok(fn_once) => fn_once, + Err(..) => return false + }; - opt_is_fn.is_some() - } else { - false - } + self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| { + let fn_once_substs = + Substs::new_trait(vec![self.next_ty_var()], vec![], ty); + let trait_ref = + ty::TraitRef::new(fn_once, + tcx.mk_substs(fn_once_substs)); + let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let obligation = Obligation::misc(span, + self.body_id, + poly_trait_ref + .to_predicate()); + SelectionContext::new(self).evaluate_obligation(&obligation) + })) } } } + pub fn report_method_error(&self, span: Span, rcvr_ty: Ty<'tcx>, @@ -384,15 +369,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return is_local(self.resolve_type_vars_with_obligations(rcvr_ty)); } - self.autoderef(span, rcvr_ty, || None, - check::UnresolvedTypeAction::Ignore, ty::NoPreference, - |ty, _| { - if is_local(ty) { - Some(()) - } else { - None - } - }).2.is_some() + self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty)) } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 264003bb62b8..5dd00cf3666a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -129,6 +129,7 @@ use rustc_back::slice; use rustc_const_eval::eval_repeat_count; mod assoc; +mod autoderef; pub mod dropck; pub mod _match; pub mod writeback; @@ -1412,17 +1413,6 @@ impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { } } -/// Whether `autoderef` requires types to resolve. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum UnresolvedTypeAction { - /// Produce an error and return `TyError` whenever a type cannot - /// be resolved (i.e. it is `TyInfer`). - Error, - /// Go on without emitting any errors, and return the unresolved - /// type. Useful for probing, e.g. in coercions. - Ignore -} - /// Controls whether the arguments are tupled. This is used for the call /// operator. /// @@ -2228,120 +2218,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` - /// to decide whether to terminate the loop. Returns the final type and number of - /// derefs that it performed. - /// - /// Note: this method does not modify the adjustments table. The caller is responsible for - /// inserting an AutoAdjustment record into the `self` using one of the suitable methods. - pub fn autoderef<'b, E, I, T, F>(&self, - sp: Span, - base_ty: Ty<'tcx>, - maybe_exprs: E, - unresolved_type_action: UnresolvedTypeAction, - mut lvalue_pref: LvaluePreference, - mut should_stop: F) - -> (Ty<'tcx>, usize, Option) - // FIXME(eddyb) use copyable iterators when that becomes ergonomic. - where E: Fn() -> I, - I: IntoIterator, - F: FnMut(Ty<'tcx>, usize) -> Option, - { - debug!("autoderef(base_ty={:?}, lvalue_pref={:?})", - base_ty, lvalue_pref); - - let mut t = base_ty; - for autoderefs in 0..self.tcx.sess.recursion_limit.get() { - let resolved_t = match unresolved_type_action { - UnresolvedTypeAction::Error => { - self.structurally_resolved_type(sp, t) - } - UnresolvedTypeAction::Ignore => { - // We can continue even when the type cannot be resolved - // (i.e. it is an inference variable) because `Ty::builtin_deref` - // and `try_overloaded_deref` both simply return `None` - // in such a case without producing spurious errors. - self.resolve_type_vars_if_possible(&t) - } - }; - if resolved_t.references_error() { - return (resolved_t, autoderefs, None); - } - - match should_stop(resolved_t, autoderefs) { - Some(x) => return (resolved_t, autoderefs, Some(x)), - None => {} - } - - // Otherwise, deref if type is derefable: - - // Super subtle: it might seem as though we should - // pass `opt_expr` to `try_overloaded_deref`, so that - // the (implicit) autoref of using an overloaded deref - // would get added to the adjustment table. However we - // do not do that, because it's kind of a - // "meta-adjustment" -- instead, we just leave it - // unrecorded and know that there "will be" an - // autoref. regionck and other bits of the code base, - // when they encounter an overloaded autoderef, have - // to do some reconstructive surgery. This is a pretty - // complex mess that is begging for a proper MIR. - let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) { - mt - } else if let Some(method) = self.try_overloaded_deref(sp, None, - resolved_t, lvalue_pref) { - for expr in maybe_exprs() { - let method_call = MethodCall::autoderef(expr.id, autoderefs as u32); - self.tables.borrow_mut().method_map.insert(method_call, method); - } - self.make_overloaded_lvalue_return_type(method) - } else { - return (resolved_t, autoderefs, None); - }; - - t = mt.ty; - if mt.mutbl == hir::MutImmutable { - lvalue_pref = NoPreference; - } - } - - // We've reached the recursion limit, error gracefully. - span_err!(self.tcx.sess, sp, E0055, - "reached the recursion limit while auto-dereferencing {:?}", - base_ty); - (self.tcx.types.err, 0, None) - } - - fn try_overloaded_deref(&self, - span: Span, - base_expr: Option<&hir::Expr>, - base_ty: Ty<'tcx>, - lvalue_pref: LvaluePreference) - -> Option> - { - // Try DerefMut first, if preferred. - let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) { - (PreferMutLvalue, Some(trait_did)) => { - self.lookup_method_in_trait(span, base_expr, - token::intern("deref_mut"), trait_did, - base_ty, None) - } - _ => None - }; - - // Otherwise, fall back to Deref. - let method = match (method, self.tcx.lang_items.deref_trait()) { - (None, Some(trait_did)) => { - self.lookup_method_in_trait(span, base_expr, - token::intern("deref"), trait_did, - base_ty, None) - } - (method, _) => method - }; - - method - } - /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait /// returns a type of `&T`, but the actual type we assign to the /// *expression* is `T`. So this function just peels off the return @@ -2371,29 +2247,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // autoderef that normal method probing does. They could likely be // consolidated. - let (ty, autoderefs, final_mt) = self.autoderef(base_expr.span, - base_ty, - || Some(base_expr), - UnresolvedTypeAction::Error, - lvalue_pref, - |adj_ty, idx| { - self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, - adj_ty, idx, false, lvalue_pref, idx_ty) - }); + let mut autoderef = self.autoderef(base_expr.span, base_ty); - if final_mt.is_some() { - return final_mt; - } + while let Some((adj_ty, autoderefs)) = autoderef.next() { + if let Some(final_mt) = self.try_index_step( + MethodCall::expr(expr.id), + expr, base_expr, adj_ty, autoderefs, + false, lvalue_pref, idx_ty) + { + autoderef.finalize(lvalue_pref, Some(base_expr)); + return Some(final_mt); + } - // After we have fully autoderef'd, if the resulting type is [T; n], then - // do a final unsized coercion to yield [T]. - if let ty::TyArray(element_ty, _) = ty.sty { - let adjusted_ty = self.tcx.mk_slice(element_ty); - self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, - adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) - } else { - None + if let ty::TyArray(element_ty, _) = adj_ty.sty { + autoderef.finalize(lvalue_pref, Some(base_expr)); + let adjusted_ty = self.tcx.mk_slice(element_ty); + return self.try_index_step( + MethodCall::expr(expr.id), expr, base_expr, + adjusted_ty, autoderefs, true, lvalue_pref, idx_ty); + } } + autoderef.unambiguous_final_ty(); + None } /// To type-check `base_expr[index_expr]`, we progressively autoderef @@ -3034,32 +2909,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(base)); let mut private_candidate = None; - let (_, autoderefs, field_ty) = self.autoderef(expr.span, - expr_t, - || Some(base), - UnresolvedTypeAction::Error, - lvalue_pref, - |base_t, _| { - if let ty::TyStruct(base_def, substs) = base_t.sty { - debug!("struct named {:?}", base_t); - if let Some(field) = base_def.struct_variant().find_field_named(field.node) { - let field_ty = self.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { - return Some(field_ty); - } - private_candidate = Some((base_def.did, field_ty)); + let mut autoderef = self.autoderef(expr.span, expr_t); + while let Some((base_t, autoderefs)) = autoderef.next() { + if let ty::TyStruct(base_def, substs) = base_t.sty { + debug!("struct named {:?}", base_t); + if let Some(field) = base_def.struct_variant().find_field_named(field.node) { + let field_ty = self.field_ty(expr.span, field, substs); + if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { + autoderef.finalize(lvalue_pref, Some(base)); + self.write_ty(expr.id, field_ty); + self.write_autoderef_adjustment(base.id, autoderefs); + return; } + private_candidate = Some((base_def.did, field_ty)); } - None - }); - match field_ty { - Some(field_ty) => { - self.write_ty(expr.id, field_ty); - self.write_autoderef_adjustment(base.id, autoderefs); - return; } - None => {} } + autoderef.unambiguous_final_ty(); if let Some((did, field_ty)) = private_candidate { let struct_path = self.tcx().item_path_str(did); @@ -3132,42 +2998,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.expr_ty(base)); let mut private_candidate = None; let mut tuple_like = false; - let (_, autoderefs, field_ty) = self.autoderef(expr.span, - expr_t, - || Some(base), - UnresolvedTypeAction::Error, - lvalue_pref, - |base_t, _| { - let (base_def, substs) = match base_t.sty { - ty::TyStruct(base_def, substs) => (base_def, substs), - ty::TyTuple(ref v) => { - tuple_like = true; - return if idx.node < v.len() { Some(v[idx.node]) } else { None } - } - _ => return None, - }; - - tuple_like = base_def.struct_variant().is_tuple_struct(); - if !tuple_like { return None } - - debug!("tuple struct named {:?}", base_t); - if let Some(field) = base_def.struct_variant().fields.get(idx.node) { - let field_ty = self.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { - return Some(field_ty); - } - private_candidate = Some((base_def.did, field_ty)); + let mut autoderef = self.autoderef(expr.span, expr_t); + while let Some((base_t, autoderefs)) = autoderef.next() { + let field = match base_t.sty { + ty::TyStruct(base_def, substs) => { + tuple_like = base_def.struct_variant().is_tuple_struct(); + if !tuple_like { continue } + + debug!("tuple struct named {:?}", base_t); + base_def.struct_variant().fields.get(idx.node).and_then(|field| { + let field_ty = self.field_ty(expr.span, field, substs); + private_candidate = Some((base_def.did, field_ty)); + if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { + Some(field_ty) + } else { + None + } + }) } - None - }); - match field_ty { - Some(field_ty) => { + ty::TyTuple(ref v) => { + tuple_like = true; + v.get(idx.node).cloned() + } + _ => continue + }; + + if let Some(field_ty) = field { + autoderef.finalize(lvalue_pref, Some(base)); self.write_ty(expr.id, field_ty); self.write_autoderef_adjustment(base.id, autoderefs); return; } - None => {} } + autoderef.unambiguous_final_ty(); if let Some((did, field_ty)) = private_candidate { let struct_path = self.tcx().item_path_str(did); diff --git a/src/test/compile-fail/E0055.rs b/src/test/compile-fail/E0055.rs index cb78f4b3bb59..f86d7ec114b9 100644 --- a/src/test/compile-fail/E0055.rs +++ b/src/test/compile-fail/E0055.rs @@ -19,5 +19,4 @@ fn main() { let foo = Foo; let ref_foo = &&Foo; ref_foo.foo(); //~ ERROR E0055 - //~^ ERROR E0275 } diff --git a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs b/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs index 497b0e63edfc..764d05be879b 100644 --- a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs +++ b/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs @@ -99,7 +99,7 @@ fn assign_field1<'a>(x: Own) { } fn assign_field2<'a>(x: &'a Own) { - x.y = 3; //~ ERROR cannot assign + x.y = 3; //~ ERROR cannot borrow } fn assign_field3<'a>(x: &'a mut Own) { diff --git a/src/test/compile-fail/issue-24819.rs b/src/test/compile-fail/issue-24819.rs new file mode 100644 index 000000000000..52f5f1cd079e --- /dev/null +++ b/src/test/compile-fail/issue-24819.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashSet; + +fn main() { + let mut v = Vec::new(); + foo(&mut v); + //~^ ERROR mismatched types + //~| expected struct `std::collections::HashSet`, found struct `std::vec::Vec` +} + +fn foo(h: &mut HashSet) { +} From 8ee22aedce75a2f062bbadb39906bd1db4a74fb8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 23:03:52 +0200 Subject: [PATCH 119/179] threaded a `ty::ParameterEnvironment` for the current node id via the associated Ctxt item. used this to address a long-standing wart/bug in how filtering-out of values with type impl'ing `Copy` was done. --- .../borrowck/mir/dataflow/graphviz.rs | 8 ++-- .../borrowck/mir/dataflow/impls.rs | 37 ++++++++++--------- .../borrowck/mir/dataflow/mod.rs | 6 +-- .../borrowck/mir/dataflow/sanity_check.rs | 14 ++++--- src/librustc_borrowck/borrowck/mir/mod.rs | 35 +++++++++++------- 5 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 0d1443ede410..588160fff692 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -24,7 +24,7 @@ use std::marker::PhantomData; use std::mem; use std::path::Path; -use super::super::gather_moves::{MoveData}; +use super::super::MoveDataParamEnv; use super::super::MirBorrowckCtxtPreDataflow; use bitslice::bits_to_string; use indexed_set::{Idx, IdxSet}; @@ -79,7 +79,7 @@ impl DataflowState { } pub trait MirWithFlowState<'tcx> { - type BD: BitDenotation>; + type BD: BitDenotation>; fn node_id(&self) -> NodeId; fn mir(&self) -> &Mir<'tcx>; fn analysis_ctxt(&self) -> &::Ctxt; @@ -87,7 +87,7 @@ pub trait MirWithFlowState<'tcx> { } impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where 'a, 'tcx: 'a, BD: BitDenotation> + where 'a, 'tcx: 'a, BD: BitDenotation> { type BD = BD; fn node_id(&self) -> NodeId { self.node_id } @@ -109,7 +109,7 @@ pub fn print_borrowck_graph_to<'a, 'tcx, BD, P>( path: &Path, render_idx: P) -> io::Result<()> - where BD: BitDenotation>, + where BD: BitDenotation>, P: for <'b> Fn(&'b BD::Ctxt, BD::Idx) -> &'b Debug { let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx }; diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index c580dc8551f2..e3435ed99050 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -12,7 +12,8 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir}; use super::super::gather_moves::{Location}; -use super::super::gather_moves::{MoveData, MoveOutIndex, MovePathIndex}; +use super::super::gather_moves::{MoveOutIndex, MovePathIndex}; +use super::super::MoveDataParamEnv; use super::super::DropFlagState; use super::super::drop_flag_effects_for_function_entry; use super::super::drop_flag_effects_for_location; @@ -226,10 +227,10 @@ impl<'a, 'tcx> DefinitelyInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; - type Ctxt = MoveData<'tcx>; + type Ctxt = MoveDataParamEnv<'tcx>; fn name() -> &'static str { "maybe_init" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.move_paths.len() + ctxt.move_data.move_paths.len() } fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets) @@ -276,8 +277,8 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, ctxt, + let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); + on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, move_path_index, |mpi| { in_out.add(&mpi); }); } @@ -285,10 +286,10 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; - type Ctxt = MoveData<'tcx>; + type Ctxt = MoveDataParamEnv<'tcx>; fn name() -> &'static str { "maybe_uninit" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.move_paths.len() + ctxt.move_data.move_paths.len() } // sets on_entry bits for Arg lvalues @@ -338,8 +339,8 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, ctxt, + let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); + on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, move_path_index, |mpi| { in_out.remove(&mpi); }); } @@ -347,10 +348,10 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { type Idx = MovePathIndex; - type Ctxt = MoveData<'tcx>; + type Ctxt = MoveDataParamEnv<'tcx>; fn name() -> &'static str { "definite_init" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.move_paths.len() + ctxt.move_data.move_paths.len() } // sets on_entry bits for Arg lvalues @@ -399,8 +400,8 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, ctxt, + let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); + on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, move_path_index, |mpi| { in_out.add(&mpi); }); } @@ -408,10 +409,10 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { type Idx = MoveOutIndex; - type Ctxt = MoveData<'tcx>; + type Ctxt = MoveDataParamEnv<'tcx>; fn name() -> &'static str { "moving_out" } fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize { - ctxt.moves.len() + ctxt.move_data.moves.len() } fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets) { @@ -423,7 +424,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { sets: &mut BlockSets, bb: repr::BasicBlock, idx: usize) { - let (tcx, mir, move_data) = (self.tcx, self.mir, ctxt); + let (tcx, mir, move_data) = (self.tcx, self.mir, &ctxt.move_data); let stmt = &mir.basic_block_data(bb).statements[idx]; let loc_map = &move_data.loc_map; let path_map = &move_data.path_map; @@ -463,7 +464,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { bb: repr::BasicBlock, statements_len: usize) { - let (mir, move_data) = (self.mir, ctxt); + let (mir, move_data) = (self.mir, &ctxt.move_data); let term = mir.basic_block_data(bb).terminator.as_ref().unwrap(); let loc_map = &move_data.loc_map; let loc = Location { block: bb, index: statements_len }; @@ -482,7 +483,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { _call_bb: repr::BasicBlock, _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { - let move_data = ctxt; + let move_data = &ctxt.move_data; let move_path_index = move_data.rev_lookup.find(dest_lval); let bits_per_block = self.bits_per_block(ctxt); diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index f91bd88d68f0..c105a0997017 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -18,7 +18,7 @@ use std::path::PathBuf; use std::usize; use super::MirBorrowckCtxtPreDataflow; -use super::gather_moves::{MoveData}; +use super::MoveDataParamEnv; use bitslice::{bitwise, BitwiseOperator}; use indexed_set::{Idx, IdxSet, OwnIdxSet}; @@ -36,7 +36,7 @@ pub trait Dataflow { } impl<'a, 'tcx: 'a, BD> Dataflow for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation> + DataflowOperator + where BD: BitDenotation> + DataflowOperator { fn dataflow

(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug { self.flow_state.build_sets(); @@ -140,7 +140,7 @@ fn dataflow_path(context: &str, prepost: &str, path: &str) -> PathBuf { } impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> - where BD: BitDenotation> + where BD: BitDenotation> { fn pre_dataflow_instrumentation

(&self, p: P) -> io::Result<()> where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 221768994942..74dc921b0bba 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -15,7 +15,8 @@ use syntax::codemap::Span; use rustc::ty::{self, TyCtxt}; use rustc::mir::repr::{self, Mir}; -use super::super::gather_moves::{MoveData, MovePathIndex}; +use super::super::gather_moves::{MovePathIndex}; +use super::super::MoveDataParamEnv; use super::BitDenotation; use super::DataflowResults; @@ -41,7 +42,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _attributes: &[ast::Attribute], flow_ctxt: &O::Ctxt, results: &DataflowResults) - where O: BitDenotation, Idx=MovePathIndex> + where O: BitDenotation, Idx=MovePathIndex> { debug!("sanity_check_via_rustc_peek id: {:?}", id); // FIXME: this is not DRY. Figure out way to abstract this and @@ -56,11 +57,12 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, - move_data: &O::Ctxt, + ctxt: &O::Ctxt, results: &DataflowResults, bb: repr::BasicBlock) where - O: BitDenotation, Idx=MovePathIndex> + O: BitDenotation, Idx=MovePathIndex> { + let move_data = &ctxt.move_data; let bb_data = mir.basic_block_data(bb); let &repr::BasicBlockData { ref statements, ref terminator, @@ -127,7 +129,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.sess.span_err(span, msg); } } - + let lhs_mpi = move_data.rev_lookup.find(lvalue); debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}", @@ -135,7 +137,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // reset GEN and KILL sets before emulating their effect. for e in sets.gen_set.words_mut() { *e = 0; } for e in sets.kill_set.words_mut() { *e = 0; } - results.0.operator.statement_effect(move_data, &mut sets, bb, j); + results.0.operator.statement_effect(ctxt, &mut sets, bb, j); sets.on_entry.union(sets.gen_set); sets.on_entry.subtract(sets.kill_set); } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 4b77e4c865b5..1b9d08bade7c 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -50,6 +50,11 @@ fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option { + move_data: MoveData<'tcx>, + param_env: ty::ParameterEnvironment<'tcx>, +} + pub fn borrowck_mir<'a, 'tcx: 'a>( bcx: &mut BorrowckCtxt<'a, 'tcx>, fk: FnKind, @@ -72,21 +77,23 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( let tcx = bcx.tcx; let move_data = MoveData::gather_moves(mir, tcx); + let param_env = ty::ParameterEnvironment::for_item(tcx, id); + let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let flow_inits = - do_dataflow(tcx, mir, id, attributes, &move_data, MaybeInitializedLvals::new(tcx, mir)); + do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeInitializedLvals::new(tcx, mir)); let flow_uninits = - do_dataflow(tcx, mir, id, attributes, &move_data, MaybeUninitializedLvals::new(tcx, mir)); + do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeUninitializedLvals::new(tcx, mir)); let flow_def_inits = - do_dataflow(tcx, mir, id, attributes, &move_data, DefinitelyInitializedLvals::new(tcx, mir)); + do_dataflow(tcx, mir, id, attributes, &mdpe, DefinitelyInitializedLvals::new(tcx, mir)); if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() { - dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &move_data, &flow_inits); + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_inits); } if has_rustc_mir_with(attributes, "rustc_peek_maybe_uninit").is_some() { - dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &move_data, &flow_uninits); + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_uninits); } if has_rustc_mir_with(attributes, "rustc_peek_definite_init").is_some() { - dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &move_data, &flow_def_inits); + dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_def_inits); } if has_rustc_mir_with(attributes, "stop_after_dataflow").is_some() { @@ -97,7 +104,7 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( bcx: bcx, mir: mir, node_id: id, - move_data: move_data, + move_data: mdpe.move_data, flow_inits: flow_inits, flow_uninits: flow_uninits, }; @@ -115,7 +122,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, attributes: &[ast::Attribute], ctxt: &BD::Ctxt, bd: BD) -> DataflowResults - where BD: BitDenotation> + DataflowOperator + where BD: BitDenotation> + DataflowOperator { use syntax::attr::AttrMetaMethods; @@ -145,7 +152,7 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, flow_state: DataflowAnalysis::new(tcx, mir, ctxt, bd), }; - mbcx.dataflow(|move_data, i| &move_data.move_paths[i]); + mbcx.dataflow(|ctxt, i| &ctxt.move_data.move_paths[i]); mbcx.flow_state.results() } @@ -253,10 +260,11 @@ fn on_all_children_bits<'a, 'tcx, F>( fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, - move_data: &MoveData<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, mut callback: F) where F: FnMut(MovePathIndex, DropFlagState) { + let move_data = &ctxt.move_data; for i in 0..(mir.arg_decls.len() as u32) { let lvalue = repr::Lvalue::Arg(i); let move_path_index = move_data.rev_lookup.find(&lvalue); @@ -269,11 +277,13 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( fn drop_flag_effects_for_location<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, - move_data: &MoveData<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, loc: Location, mut callback: F) where F: FnMut(MovePathIndex, DropFlagState) { + let move_data = &ctxt.move_data; + let param_env = &ctxt.param_env; debug!("drop_flag_effects_for_location({:?})", loc); // first, move out of the RHS @@ -284,8 +294,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( // don't move out of non-Copy things if let MovePathContent::Lvalue(ref lvalue) = move_data.move_paths[path].content { let ty = mir.lvalue_ty(tcx, lvalue).to_ty(tcx); - let empty_param_env = tcx.empty_parameter_environment(); - if !ty.moves_by_default(tcx, &empty_param_env, DUMMY_SP) { + if !ty.moves_by_default(tcx, param_env, DUMMY_SP) { continue; } } From 53c3b579b0b5e6ec69b60d128a113ba9a8a280a1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 23:08:07 +0200 Subject: [PATCH 120/179] placate tidy in `mir::dataflow::graphviz`. --- .../borrowck/mir/dataflow/graphviz.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 588160fff692..63c11fb3545b 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -132,7 +132,9 @@ fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec { impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> where MWF: MirWithFlowState<'tcx>, - P: for <'b> Fn(&'b ::Ctxt, ::Idx) -> &'b Debug, + P: for <'b> Fn(&'b ::Ctxt, + ::Idx) + -> &'b Debug, { type Node = Node; type Edge = Edge; @@ -243,8 +245,10 @@ impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P> |w| { let ctxt = self.mbcx.analysis_ctxt(); let flow = self.mbcx.flow_state(); - let gen_interp = flow.interpret_set(ctxt, flow.sets.gen_set_for(i), &self.render_idx); - let kill_interp = flow.interpret_set(ctxt, flow.sets.kill_set_for(i), &self.render_idx); + let gen_interp = + flow.interpret_set(ctxt, flow.sets.gen_set_for(i), &self.render_idx); + let kill_interp = + flow.interpret_set(ctxt, flow.sets.kill_set_for(i), &self.render_idx); chunked_present_left(w, &gen_interp[..], chunk_size)?; let bits_per_block = flow.sets.bits_per_block(); { From d3c0978a6d6cd235aaab46eaf9668a92be8a21ef Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 23:08:16 +0200 Subject: [PATCH 121/179] placate tidy in `mir::dataflow`. --- src/librustc_borrowck/borrowck/mir/dataflow/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index c105a0997017..dad0c9251860 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -121,9 +121,8 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> in_out.union(sets.gen_set); in_out.subtract(sets.kill_set); } - builder.propagate_bits_into_graph_successors_of(in_out, - &mut self.changed, - (repr::BasicBlock::new(bb_idx), bb_data)); + builder.propagate_bits_into_graph_successors_of( + in_out, &mut self.changed, (repr::BasicBlock::new(bb_idx), bb_data)); } } } From 1be936fca7a2b08598ae5e641a4a6a45c14f063b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 23:08:24 +0200 Subject: [PATCH 122/179] placate tidy in `mir::gather_moves`. --- src/librustc_borrowck/borrowck/mir/gather_moves.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index e196de46ee67..45fb98df6530 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -659,7 +659,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD debug!("gather_moves Return on_move_out_lval return {:?}", source); bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); } else { - debug!("gather_moves Return on_move_out_lval assuming unreachable return {:?}", source); + debug!("gather_moves Return on_move_out_lval \ + assuming unreachable return {:?}", source); } } From 7a1c230e25da83f06c407a18f2a50698f09526d4 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 May 2016 23:08:34 +0200 Subject: [PATCH 123/179] placate tidy in compile-fail test. --- src/test/compile-fail/mir-dataflow/uninits-2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/mir-dataflow/uninits-2.rs b/src/test/compile-fail/mir-dataflow/uninits-2.rs index a2869da7eb35..e0bf42534499 100644 --- a/src/test/compile-fail/mir-dataflow/uninits-2.rs +++ b/src/test/compile-fail/mir-dataflow/uninits-2.rs @@ -19,7 +19,7 @@ use std::mem::{drop, replace}; struct S(i32); #[rustc_mir_borrowck] -#[rustc_mir(rustc_peek_maybe_uninit,stop_after_dataflow,borrowck_graphviz_postflow="/tmp/uninits-2.dot")] +#[rustc_mir(rustc_peek_maybe_uninit,stop_after_dataflow)] fn foo(x: &mut S) { // `x` is initialized here, so maybe-uninit bit is 0. From bd9d0aa35c1810b895b6a38765e34b4c0d3f23bf Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 10 May 2016 23:21:18 +0300 Subject: [PATCH 124/179] rustc: use a simpler scheme for plugin registrar symbol names. --- src/librustc/session/mod.rs | 10 ++++++++++ src/librustc_metadata/creader.rs | 14 +++++++++----- src/librustc_metadata/decoder.rs | 8 -------- src/librustc_plugin/load.rs | 3 ++- src/librustc_trans/base.rs | 6 ++++++ 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 907241d1746d..ab9187a835da 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -9,6 +9,8 @@ // except according to those terms. use dep_graph::DepGraph; +use hir::def_id::DefIndex; +use hir::svh::Svh; use lint; use middle::cstore::CrateStore; use middle::dependency_format; @@ -312,6 +314,14 @@ impl Session { pub fn nonzeroing_move_hints(&self) -> bool { self.opts.debugging_opts.enable_nonzeroing_move_hints } + + /// Returns the symbol name for the registrar function, + /// given the crate Svh and the function DefIndex. + pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex) + -> String { + format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize()) + } + pub fn sysroot<'a>(&'a self) -> &'a Path { match self.opts.maybe_sysroot { Some (ref sysroot) => sysroot, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index ad6bb2dbac22..2025045cc8f5 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -17,6 +17,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob}; use decoder; use loader::{self, CratePaths}; +use rustc::hir::def_id::DefIndex; use rustc::hir::svh::Svh; use rustc::dep_graph::{DepGraph, DepNode}; use rustc::session::{config, Session}; @@ -610,9 +611,10 @@ impl<'a> CrateReader<'a> { macros } - /// Look for a plugin registrar. Returns library path and symbol name. + /// Look for a plugin registrar. Returns library path, crate + /// SVH and DefIndex of the registrar function. pub fn find_plugin_registrar(&mut self, span: Span, name: &str) - -> Option<(PathBuf, String)> { + -> Option<(PathBuf, Svh, DefIndex)> { let ekrate = self.read_extension_crate(span, &CrateInfo { name: name.to_string(), ident: name.to_string(), @@ -630,12 +632,14 @@ impl<'a> CrateReader<'a> { span_fatal!(self.sess, span, E0456, "{}", &message[..]); } + let svh = decoder::get_crate_hash(ekrate.metadata.as_slice()); let registrar = - decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()) - .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id)); + decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()); match (ekrate.dylib.as_ref(), registrar) { - (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)), + (Some(dylib), Some(reg)) => { + Some((dylib.to_path_buf(), svh, reg)) + } (None, Some(_)) => { span_err!(self.sess, span, E0457, "plugin `{}` only found in rlib format, but must be available \ diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b6f35074b7dc..7f79df97852b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -644,14 +644,6 @@ pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String { return item_symbol(cdata.lookup_item(id)); } -/// If you have a crate_metadata, call get_symbol instead -pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String { - let index = load_index(data); - let pos = index.lookup_item(data, id).unwrap(); - let doc = reader::doc_at(data, pos as usize).unwrap().doc; - item_symbol(doc) -} - /// Iterates over the language items in the given crate. pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where F: FnMut(DefIndex, usize) -> bool, diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 036e46c38039..11e1841f7493 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -101,7 +101,8 @@ impl<'a> PluginLoader<'a> { fn load_plugin(&mut self, span: Span, name: &str, args: Vec>) { let registrar = self.reader.find_plugin_registrar(span, name); - if let Some((lib, symbol)) = registrar { + if let Some((lib, svh, index)) = registrar { + let symbol = self.sess.generate_plugin_registrar_symbol(&svh, index); let fun = self.dylink_registrar(span, lib, symbol); self.plugins.push(PluginRegistrar { fun: fun, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 992e07fa7449..451bfbc83bc1 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2443,6 +2443,12 @@ pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> String { let id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); + if ccx.sess().plugin_registrar_fn.get() == Some(id) { + let svh = &ccx.link_meta().crate_hash; + let idx = instance.def.index; + return ccx.sess().generate_plugin_registrar_symbol(svh, idx); + } + match ccx.external_srcs().borrow().get(&id) { Some(&did) => { let sym = ccx.sess().cstore.item_symbol(did); From d92412f7d5cdd9bcc03c950f392ac8328a43c6b6 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 10 May 2016 23:24:17 +0300 Subject: [PATCH 125/179] trans: remove unused symbol_names::exported_name_with_suffix. --- src/librustc_trans/back/symbol_names.rs | 30 +++++-------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 0cf82d66b2b6..0495cf5eb671 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -116,7 +116,7 @@ pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> def_path_to_string(tcx, &def_path) } -pub fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String { +fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String { let mut s = String::with_capacity(def_path.data.len() * 16); s.push_str(&tcx.crate_name(def_path.krate)); @@ -187,14 +187,13 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &Instance<'tcx>, - suffix: Option<&str>) - -> String { +pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: &Instance<'tcx>) + -> String { let &Instance { def: mut def_id, ref substs } = instance; - debug!("exported_name_with_opt_suffix(def_id={:?}, substs={:?}, suffix={:?})", - def_id, substs, suffix); + debug!("exported_name(def_id={:?}, substs={:?})", + def_id, substs); if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) { @@ -242,10 +241,6 @@ fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; ccx.tcx().push_item_path(&mut buffer, def_id); - if let Some(suffix) = suffix { - buffer.push(suffix); - } - mangle(buffer.names.into_iter(), Some(&hash[..])) } @@ -264,19 +259,6 @@ impl ItemPathBuffer for SymbolPathBuffer { } } -pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &Instance<'tcx>) - -> String { - exported_name_with_opt_suffix(ccx, instance, None) -} - -pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &Instance<'tcx>, - suffix: &str) - -> String { - exported_name_with_opt_suffix(ccx, instance, Some(suffix)) -} - /// Only symbols that are invisible outside their compilation unit should use a /// name generated by this function. pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, From 5112360817ebd496c0d292f0cf7ea3fdfe9d5548 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 23 May 2016 22:29:17 -0700 Subject: [PATCH 126/179] std: Use memalign, not posix_memalign, on Android We've gotten requests to move our Android support as far back as API level 9 where unfortunately the `posix_memalign` API wasn't implemented yet. Thankfully, however, the `memalign` API was and it appears to be usable with `free` on the Android platform (see comments included in commit). This should help fix some of the last few test failures when compiling against API level 9. --- src/liballoc_system/lib.rs | 41 +++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index a22299c5e1a5..9eade937bfb4 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -80,13 +80,40 @@ mod imp { if align <= MIN_ALIGN { libc::malloc(size as libc::size_t) as *mut u8 } else { - let mut out = ptr::null_mut(); - let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t); - if ret != 0 { - ptr::null_mut() - } else { - out as *mut u8 - } + aligned_malloc(size, align) + } + } + + #[cfg(target_os = "android")] + unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 { + // On android we currently target API level 9 which unfortunately + // doesn't have the `posix_memalign` API used below. Instead we use + // `memalign`, but this unfortunately has the property on some systems + // where the memory returned cannot be deallocated by `free`! + // + // Upon closer inspection, however, this appears to work just fine with + // Android, so for this platform we should be fine to call `memalign` + // (which is present in API level 9). Some helpful references could + // possibly be chromium using memalign [1], attempts at documenting that + // memalign + free is ok [2] [3], or the current source of chromium + // which still uses memalign on android [4]. + // + // [1]: https://codereview.chromium.org/10796020/ + // [2]: https://code.google.com/p/android/issues/detail?id=35391 + // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 + // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ + // /memory/aligned_memory.cc + libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8 + } + + #[cfg(not(target_os = "android"))] + unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 { + let mut out = ptr::null_mut(); + let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t); + if ret != 0 { + ptr::null_mut() + } else { + out as *mut u8 } } From 5753191d66694f6f7a347179dbda174143ab5279 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 25 May 2016 01:34:17 +0300 Subject: [PATCH 127/179] trans: move exported_name's logic into symbol_names. --- src/librustc_trans/back/symbol_names.rs | 64 +++++++++++++++++-------- src/librustc_trans/base.rs | 44 +---------------- src/librustc_trans/callee.rs | 5 +- src/librustc_trans/closure.rs | 2 +- src/librustc_trans/consts.rs | 9 ++-- src/librustc_trans/context.rs | 4 ++ src/librustc_trans/monomorphize.rs | 2 +- src/librustc_trans/symbol_names_test.rs | 2 +- 8 files changed, 62 insertions(+), 70 deletions(-) diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 0495cf5eb671..dffd0beafe51 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -97,17 +97,18 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -use common::{CrateContext, gensym_name}; +use common::{CrateContext, SharedCrateContext, gensym_name}; use monomorphize::Instance; use util::sha2::{Digest, Sha256}; -use rustc::middle::cstore; +use rustc::middle::{cstore, weak_lang_items}; use rustc::hir::def_id::DefId; use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc::ty::item_path::{ItemPathBuffer, RootMode}; +use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::hir::map::definitions::{DefPath, DefPathData}; use std::fmt::Write; +use syntax::attr; use syntax::parse::token::{self, InternedString}; use serialize::hex::ToHex; @@ -134,7 +135,7 @@ fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) s } -fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // path to the item this name is for def_path: &DefPath, @@ -152,9 +153,9 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("get_symbol_hash(def_path={:?}, parameters={:?})", def_path, parameters); - let tcx = ccx.tcx(); + let tcx = scx.tcx(); - let mut hash_state = ccx.symbol_hasher().borrow_mut(); + let mut hash_state = scx.symbol_hasher().borrow_mut(); hash_state.reset(); @@ -187,22 +188,47 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &Instance<'tcx>) +pub fn exported_name<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + instance: Instance<'tcx>) -> String { - let &Instance { def: mut def_id, ref substs } = instance; + let Instance { def: def_id, ref substs } = instance; debug!("exported_name(def_id={:?}, substs={:?})", def_id, substs); - if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { - if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) { - def_id = src_def_id; + let node_id = scx.tcx().map.as_local_node_id(instance.def); + + if let Some(id) = node_id { + if scx.sess().plugin_registrar_fn.get() == Some(id) { + let svh = &scx.link_meta().crate_hash; + let idx = instance.def.index; + return scx.sess().generate_plugin_registrar_symbol(svh, idx); } } - let def_path = ccx.tcx().def_path(def_id); - assert_eq!(def_path.krate, def_id.krate); + // FIXME(eddyb) Precompute a custom symbol name based on attributes. + let attrs; + let attrs = if let Some(id) = node_id { + scx.tcx().map.attrs(id) + } else { + attrs = scx.sess().cstore.item_attrs(def_id); + &attrs[..] + }; + + if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), attrs) { + // Use provided name + return name.to_string(); + } + + if attr::contains_name(attrs, "no_mangle") { + // Don't mangle + return scx.tcx().item_name(instance.def).as_str().to_string() + } + if let Some(name) = weak_lang_items::link_name(attrs) { + return name.to_string(); + } + + let def_path = scx.tcx().def_path(def_id); // We want to compute the "type" of this item. Unfortunately, some // kinds of items (e.g., closures) don't have an entry in the @@ -211,11 +237,11 @@ pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let mut ty_def_id = def_id; let instance_ty; loop { - let key = ccx.tcx().def_key(ty_def_id); + let key = scx.tcx().def_key(ty_def_id); match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = ccx.tcx().lookup_item_type(ty_def_id); + instance_ty = scx.tcx().lookup_item_type(ty_def_id); break; } _ => { @@ -232,9 +258,9 @@ pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = ccx.tcx().erase_regions(&instance_ty.ty); + let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); - let hash = get_symbol_hash(ccx, &def_path, instance_ty, substs.types.as_slice()); + let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_slice()); let mut buffer = SymbolPathBuffer { names: Vec::with_capacity(def_path.data.len()) @@ -271,7 +297,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> data: vec![], krate: cstore::LOCAL_CRATE, }; - let hash = get_symbol_hash(ccx, &def_path, t, &[]); + let hash = get_symbol_hash(ccx.shared(), &def_path, t, &[]); mangle(path.iter().cloned(), Some(&hash[..])) } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 451bfbc83bc1..f6a2b82fb166 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2437,47 +2437,6 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { } } -pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>, - attrs: &[ast::Attribute]) - -> String { - let id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); - - if ccx.sess().plugin_registrar_fn.get() == Some(id) { - let svh = &ccx.link_meta().crate_hash; - let idx = instance.def.index; - return ccx.sess().generate_plugin_registrar_symbol(svh, idx); - } - - match ccx.external_srcs().borrow().get(&id) { - Some(&did) => { - let sym = ccx.sess().cstore.item_symbol(did); - debug!("found item {} in other crate...", sym); - return sym; - } - None => {} - } - - match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) { - // Use provided name - Some(name) => name.to_string(), - _ => { - if attr::contains_name(attrs, "no_mangle") { - // Don't mangle - ccx.tcx().map.name(id).as_str().to_string() - } else { - match weak_lang_items::link_name(attrs) { - Some(name) => name.to_string(), - None => { - // Usual name mangling - symbol_names::exported_name(ccx, &instance) - } - } - } - } - } -} - pub fn imported_name(name: ast::Name, attrs: &[ast::Attribute]) -> InternedString { match attr::first_attr_value_str_by_name(attrs, "link_name") { Some(ln) => ln.clone(), @@ -2840,7 +2799,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_symbols.extend(syms.into_iter().filter(|did| { sess.cstore.is_extern_item(shared_ccx.tcx(), *did) }).map(|did| { - sess.cstore.item_symbol(did) + let instance = Instance::mono(shared_ccx.tcx(), did); + symbol_names::exported_name(&shared_ccx, instance) })); } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index c0c5ea818b2d..bdeb1a6270f9 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -512,7 +512,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Some(hir_map::NodeImplItem(&hir::ImplItem { ref attrs, id, span, node: hir::ImplItemKind::Method(..), .. })) => { - let sym = exported_name(ccx, instance, attrs); + let sym = symbol_names::exported_name(ccx.shared(), instance); if declare::get_defined_value(ccx, &sym).is_some() { ccx.sess().span_fatal(span, @@ -530,7 +530,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, None => { attrs = ccx.sess().cstore.item_attrs(def_id); - (ccx.sess().cstore.item_symbol(def_id), &attrs[..], None) + let sym = symbol_names::exported_name(ccx.shared(), instance); + (sym, &attrs[..], None) } ref variant => { diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 1c393f8091ee..8d273dfe1953 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -150,7 +150,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let symbol = symbol_names::exported_name(ccx, &instance); + let symbol = symbol_names::exported_name(ccx.shared(), instance); // Compute the rust-call form of the closure call method. let sig = &tcx.closure_type(closure_id, substs).sig; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 3e876eb3d7de..6dca7fe5ed92 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -19,7 +19,8 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use {abi, adt, closure, debuginfo, expr, machine}; -use base::{self, exported_name, imported_name, push_ctxt}; +use base::{self, imported_name, push_ctxt}; +use back::symbol_names; use callee::Callee; use collector; use trans_item::TransItem; @@ -1021,13 +1022,13 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) let llty = type_of::type_of(ccx, ty); match ccx.tcx().map.get(id) { hir_map::NodeItem(&hir::Item { - ref attrs, span, node: hir::ItemStatic(..), .. + span, node: hir::ItemStatic(..), .. }) => { // If this static came from an external crate, then // we need to get the symbol from metadata instead of // using the current crate's name/version // information in the hash of the symbol - let sym = exported_name(ccx, instance, attrs); + let sym = symbol_names::exported_name(ccx.shared(), instance); debug!("making {}", sym); // Create the global before evaluating the initializer; @@ -1104,7 +1105,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } else { // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global - let name = ccx.sess().cstore.item_symbol(def_id); + let name = symbol_names::exported_name(ccx.shared(), instance); let g = declare::declare_global(ccx, &name, type_of::type_of(ccx, ty)); // Thread-local statics in some other crate need to *always* be linked // against in a thread-local fashion, so we need to be sure to apply the diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 4d6c4cdcc6b0..95d56432e1e3 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -504,6 +504,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { scheme.generics.regions.map(|_| ty::ReStatic))) } + pub fn symbol_hasher(&self) -> &RefCell { + &self.symbol_hasher + } + pub fn metadata_symbol_name(&self) -> String { format!("rust_metadata_{}_{}", self.link_meta().crate_name, diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index dfaf84ecef02..e781468f96c9 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -88,7 +88,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, monomorphizing.insert(fn_id, depth + 1); } - let symbol = symbol_names::exported_name(ccx, &instance); + let symbol = symbol_names::exported_name(ccx.shared(), instance); debug!("monomorphize_fn mangled to {}", symbol); assert!(declare::get_defined_value(ccx, &symbol).is_none()); diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 284a227276dd..6777e98d4b81 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -53,7 +53,7 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names let instance = Instance::mono(self.ccx.shared(), def_id); - let name = symbol_names::exported_name(self.ccx, &instance); + let name = symbol_names::exported_name(self.ccx.shared(), instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { let path = tcx.item_path_str(def_id); From a42d394cb57fe62a263da3ab1f4a5393d0eda16b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 12 May 2016 01:25:20 +0300 Subject: [PATCH 128/179] trans: force absolute item paths within symbols. --- src/librustc/ty/item_path.rs | 36 ++++++++++++++++++++++--- src/librustc_trans/back/symbol_names.rs | 11 ++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 5246c6739d96..ee9983038b16 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -14,12 +14,38 @@ use hir::def_id::{DefId, CRATE_DEF_INDEX}; use ty::{self, Ty, TyCtxt}; use syntax::ast; +use std::cell::Cell; + +thread_local! { + static FORCE_ABSOLUTE: Cell = Cell::new(false) +} + +/// Enforces that item_path_str always returns an absolute path. +/// This is useful when building symbols that contain types, +/// where we want the crate name to be part of the symbol. +pub fn with_forced_absolute_paths R, R>(f: F) -> R { + FORCE_ABSOLUTE.with(|force| { + let old = force.get(); + force.set(true); + let result = f(); + force.set(old); + result + }) +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns a string identifying this def-id. This string is /// suitable for user output. It is relative to the current crate - /// root. + /// root, unless with_forced_absolute_paths was used. pub fn item_path_str(self, def_id: DefId) -> String { - let mut buffer = LocalPathBuffer::new(RootMode::Local); + let mode = FORCE_ABSOLUTE.with(|force| { + if force.get() { + RootMode::Absolute + } else { + RootMode::Local + } + }); + let mut buffer = LocalPathBuffer::new(mode); self.push_item_path(&mut buffer, def_id); buffer.into_string() } @@ -75,7 +101,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { RootMode::Absolute => { // In absolute mode, just write the crate name // unconditionally. - buffer.push(&self.crate_name(cnum)); + if cnum == LOCAL_CRATE { + buffer.push(&self.crate_name(cnum)); + } else { + buffer.push(&self.sess.cstore.original_crate_name(cnum)); + } } } } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index dffd0beafe51..4c166029c3e7 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -120,7 +120,11 @@ pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String { let mut s = String::with_capacity(def_path.data.len() * 16); - s.push_str(&tcx.crate_name(def_path.krate)); + if def_path.krate == cstore::LOCAL_CRATE { + s.push_str(&tcx.crate_name(def_path.krate)); + } else { + s.push_str(&tcx.sess.cstore.original_crate_name(def_path.krate)); + } s.push_str("/"); s.push_str(&tcx.crate_disambiguator(def_path.krate)); @@ -265,7 +269,10 @@ pub fn exported_name<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let mut buffer = SymbolPathBuffer { names: Vec::with_capacity(def_path.data.len()) }; - ccx.tcx().push_item_path(&mut buffer, def_id); + + item_path::with_forced_absolute_paths(|| { + scx.tcx().push_item_path(&mut buffer, def_id); + }); mangle(buffer.names.into_iter(), Some(&hash[..])) } From 28be4e6d0f8ec4e2f78768e930271fccf872334e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 12 May 2016 19:52:38 +0300 Subject: [PATCH 129/179] trans: move exported_symbol to Instance::symbol_name. --- src/librustc/middle/cstore.rs | 2 + src/librustc_metadata/csearch.rs | 5 + src/librustc_metadata/decoder.rs | 10 ++ src/librustc_metadata/encoder.rs | 2 + src/librustc_trans/back/symbol_names.rs | 148 +++++++++++--------- src/librustc_trans/base.rs | 28 ++-- src/librustc_trans/callee.rs | 47 +++---- src/librustc_trans/closure.rs | 2 +- src/librustc_trans/consts.rs | 20 ++- src/librustc_trans/monomorphize.rs | 3 +- src/librustc_trans/symbol_names_test.rs | 3 +- src/test/compile-fail/symbol-names/impl1.rs | 2 +- 12 files changed, 146 insertions(+), 126 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index e5a8c1d1b4e6..61978ca71d2f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -205,6 +205,7 @@ pub trait CrateStore<'tcx> { fn is_impl(&self, did: DefId) -> bool; fn is_default_impl(&self, impl_did: DefId) -> bool; fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool; + fn is_foreign_item(&self, did: DefId) -> bool; fn is_static_method(&self, did: DefId) -> bool; fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; fn is_typedef(&self, did: DefId) -> bool; @@ -399,6 +400,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") } fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { bug!("is_extern_item") } + fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") } fn is_static_method(&self, did: DefId) -> bool { bug!("is_static_method") } fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false } fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index b87b5492f044..5d5820251491 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -284,6 +284,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::is_extern_item(&cdata, did.index, tcx) } + fn is_foreign_item(&self, did: DefId) -> bool { + let cdata = self.get_crate_data(did.krate); + decoder::is_foreign_item(&cdata, did.index) + } + fn is_static_method(&self, def: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(def)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 7f79df97852b..2c4edcea611d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1634,6 +1634,16 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, } } +pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool { + let item_doc = cdata.lookup_item(id); + let parent_item_id = match item_parent_item(cdata, item_doc) { + None => return false, + Some(item_id) => item_id, + }; + let parent_item_doc = cdata.lookup_item(parent_item_id.index); + item_family(parent_item_doc) == ForeignMod +} + pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool { let item_doc = cdata.lookup_item(id); match item_family(item_doc) { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 928601095b07..5476b21dd8c1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1354,6 +1354,8 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); + let parent_id = ecx.tcx.map.get_parent(nitem.id); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); encode_visibility(rbml_w, &nitem.vis); match nitem.node { hir::ForeignItemFn(ref fndecl, _) => { diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 4c166029c3e7..170c8f75b505 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -103,6 +103,7 @@ use util::sha2::{Digest, Sha256}; use rustc::middle::{cstore, weak_lang_items}; use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::hir::map::definitions::{DefPath, DefPathData}; @@ -192,89 +193,100 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } -pub fn exported_name<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - instance: Instance<'tcx>) - -> String { - let Instance { def: def_id, ref substs } = instance; +impl<'a, 'tcx> Instance<'tcx> { + pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String { + let Instance { def: def_id, ref substs } = self; - debug!("exported_name(def_id={:?}, substs={:?})", - def_id, substs); + debug!("symbol_name(def_id={:?}, substs={:?})", + def_id, substs); - let node_id = scx.tcx().map.as_local_node_id(instance.def); + let node_id = scx.tcx().map.as_local_node_id(def_id); - if let Some(id) = node_id { - if scx.sess().plugin_registrar_fn.get() == Some(id) { - let svh = &scx.link_meta().crate_hash; - let idx = instance.def.index; - return scx.sess().generate_plugin_registrar_symbol(svh, idx); + if let Some(id) = node_id { + if scx.sess().plugin_registrar_fn.get() == Some(id) { + let svh = &scx.link_meta().crate_hash; + let idx = def_id.index; + return scx.sess().generate_plugin_registrar_symbol(svh, idx); + } } - } - - // FIXME(eddyb) Precompute a custom symbol name based on attributes. - let attrs; - let attrs = if let Some(id) = node_id { - scx.tcx().map.attrs(id) - } else { - attrs = scx.sess().cstore.item_attrs(def_id); - &attrs[..] - }; - if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), attrs) { - // Use provided name - return name.to_string(); - } + // FIXME(eddyb) Precompute a custom symbol name based on attributes. + let attrs = scx.tcx().get_attrs(def_id); + let is_foreign = if let Some(id) = node_id { + match scx.tcx().map.get(id) { + hir_map::NodeForeignItem(_) => true, + _ => false + } + } else { + scx.sess().cstore.is_foreign_item(def_id) + }; - if attr::contains_name(attrs, "no_mangle") { - // Don't mangle - return scx.tcx().item_name(instance.def).as_str().to_string() - } - if let Some(name) = weak_lang_items::link_name(attrs) { - return name.to_string(); - } + if let Some(name) = weak_lang_items::link_name(&attrs) { + return name.to_string(); + } - let def_path = scx.tcx().def_path(def_id); - - // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. - let mut ty_def_id = def_id; - let instance_ty; - loop { - let key = scx.tcx().def_key(ty_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) | - DefPathData::ValueNs(_) => { - instance_ty = scx.tcx().lookup_item_type(ty_def_id); - break; + if is_foreign { + if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") { + return name.to_string(); } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - ty_def_id.index = key.parent.unwrap_or_else(|| { - bug!("finding type for {:?}, encountered def-id {:?} with no \ - parent", def_id, ty_def_id); - }); + // Don't mangle foreign items. + return scx.tcx().item_name(def_id).as_str().to_string(); + } + + if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) { + // Use provided name + return name.to_string(); + } + + if attr::contains_name(&attrs, "no_mangle") { + // Don't mangle + return scx.tcx().item_name(def_id).as_str().to_string(); + } + + let def_path = scx.tcx().def_path(def_id); + + // We want to compute the "type" of this item. Unfortunately, some + // kinds of items (e.g., closures) don't have an entry in the + // item-type array. So walk back up the find the closest parent + // that DOES have an entry. + let mut ty_def_id = def_id; + let instance_ty; + loop { + let key = scx.tcx().def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | + DefPathData::ValueNs(_) => { + instance_ty = scx.tcx().lookup_item_type(ty_def_id); + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + ty_def_id.index = key.parent.unwrap_or_else(|| { + bug!("finding type for {:?}, encountered def-id {:?} with no \ + parent", def_id, ty_def_id); + }); + } } } - } - // Erase regions because they may not be deterministic when hashed - // and should not matter anyhow. - let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); + // Erase regions because they may not be deterministic when hashed + // and should not matter anyhow. + let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); - let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_slice()); + let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_slice()); - let mut buffer = SymbolPathBuffer { - names: Vec::with_capacity(def_path.data.len()) - }; + let mut buffer = SymbolPathBuffer { + names: Vec::with_capacity(def_path.data.len()) + }; - item_path::with_forced_absolute_paths(|| { - scx.tcx().push_item_path(&mut buffer, def_id); - }); + item_path::with_forced_absolute_paths(|| { + scx.tcx().push_item_path(&mut buffer, def_id); + }); - mangle(buffer.names.into_iter(), Some(&hash[..])) + mangle(buffer.names.into_iter(), Some(&hash[..])) + } } struct SymbolPathBuffer { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f6a2b82fb166..94ef80d3b858 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -30,7 +30,7 @@ pub use self::ValueOrigin::*; use super::CrateTranslation; use super::ModuleTranslation; -use back::{link, symbol_names}; +use back::link; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; @@ -2635,10 +2635,7 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet { - scx.reachable().iter().map(|x| *x).filter(|id| { - // First, only worry about nodes which have a symbol name - scx.item_symbols().borrow().contains_key(id) - }).filter(|&id| { + scx.reachable().iter().map(|x| *x).filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -2656,7 +2653,18 @@ pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet { hir_map::NodeForeignItem(..) => { scx.sess().cstore.is_statically_included_foreign_item(id) } - _ => true, + + // Only consider nodes that actually have exported symbols. + hir_map::NodeItem(&hir::Item { + node: hir::ItemStatic(..), .. }) | + hir_map::NodeItem(&hir::Item { + node: hir::ItemFn(..), .. }) | + hir_map::NodeTraitItem(&hir::TraitItem { + node: hir::MethodTraitItem(_, Some(_)), .. }) | + hir_map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(..), .. }) => true, + + _ => false } }).collect() } @@ -2775,8 +2783,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .collect(); let sess = shared_ccx.sess(); - let mut reachable_symbols = reachable_symbol_ids.iter().map(|id| { - shared_ccx.item_symbols().borrow()[id].to_string() + let mut reachable_symbols = reachable_symbol_ids.iter().map(|&id| { + let def_id = shared_ccx.tcx().map.local_def_id(id); + Instance::mono(&shared_ccx, def_id).symbol_name(&shared_ccx) }).collect::>(); if sess.entry_fn.borrow().is_some() { reachable_symbols.push("main".to_string()); @@ -2799,8 +2808,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_symbols.extend(syms.into_iter().filter(|did| { sess.cstore.is_extern_item(shared_ccx.tcx(), *did) }).map(|did| { - let instance = Instance::mono(shared_ccx.tcx(), did); - symbol_names::exported_name(&shared_ccx, instance) + Instance::mono(&shared_ccx, did).symbol_name(&shared_ccx) })); } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index bdeb1a6270f9..e7fa871d23db 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -499,44 +499,20 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return immediate_rvalue(llfn, fn_ptr_ty); } - let attrs; let local_id = ccx.tcx().map.as_local_node_id(def_id); - let maybe_node = local_id.and_then(|id| tcx.map.find(id)); - let (sym, attrs, local_item) = match maybe_node { + let local_item = match local_id.and_then(|id| tcx.map.find(id)) { Some(hir_map::NodeItem(&hir::Item { - ref attrs, id, span, node: hir::ItemFn(..), .. + span, node: hir::ItemFn(..), .. })) | Some(hir_map::NodeTraitItem(&hir::TraitItem { - ref attrs, id, span, node: hir::MethodTraitItem(_, Some(_)), .. + span, node: hir::MethodTraitItem(_, Some(_)), .. })) | Some(hir_map::NodeImplItem(&hir::ImplItem { - ref attrs, id, span, node: hir::ImplItemKind::Method(..), .. + span, node: hir::ImplItemKind::Method(..), .. })) => { - let sym = symbol_names::exported_name(ccx.shared(), instance); - - if declare::get_defined_value(ccx, &sym).is_some() { - ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", sym)); - } - - (sym, &attrs[..], Some(id)) - } - - Some(hir_map::NodeForeignItem(&hir::ForeignItem { - ref attrs, name, node: hir::ForeignItemFn(..), .. - })) => { - (imported_name(name, attrs).to_string(), &attrs[..], None) - } - - None => { - attrs = ccx.sess().cstore.item_attrs(def_id); - let sym = symbol_names::exported_name(ccx.shared(), instance); - (sym, &attrs[..], None) - } - - ref variant => { - bug!("get_fn: unexpected variant: {:?}", variant) + Some(span) } + _ => None }; // This is subtle and surprising, but sometimes we have to bitcast @@ -563,8 +539,16 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. + let sym = instance.symbol_name(ccx.shared()); let llptrty = type_of::type_of(ccx, fn_ptr_ty); let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { + if let Some(span) = local_item { + if declare::get_defined_value(ccx, &sym).is_some() { + ccx.sess().span_fatal(span, + &format!("symbol `{}` is already defined", sym)); + } + } + if common::val_ty(llfn) != llptrty { if local_item.is_some() { bug!("symbol `{}` previously declared as {:?}, now wanted as {:?}", @@ -581,7 +565,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert_eq!(common::val_ty(llfn), llptrty); debug!("get_fn: not casting pointer!"); - attributes::from_fn_attrs(ccx, attrs, llfn); + let attrs = ccx.tcx().get_attrs(def_id); + attributes::from_fn_attrs(ccx, &attrs, llfn); if local_item.is_some() { // FIXME(eddyb) Doubt all extern fn should allow unwinding. attributes::unwind(llfn, true); diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 8d273dfe1953..5e0d34c2a674 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -150,7 +150,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let symbol = symbol_names::exported_name(ccx.shared(), instance); + let symbol = instance.symbol_name(ccx.shared()); // Compute the rust-call form of the closure call method. let sig = &tcx.closure_type(closure_id, substs).sig; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 6dca7fe5ed92..bf7d1ef4d063 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -19,8 +19,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use {abi, adt, closure, debuginfo, expr, machine}; -use base::{self, imported_name, push_ctxt}; -use back::symbol_names; +use base::{self, push_ctxt}; use callee::Callee; use collector; use trans_item::TransItem; @@ -1018,6 +1017,8 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) return Datum::new(g, ty, Lvalue::new("static")); } + let sym = instance.symbol_name(ccx.shared()); + let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); match ccx.tcx().map.get(id) { @@ -1028,7 +1029,6 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) // we need to get the symbol from metadata instead of // using the current crate's name/version // information in the hash of the symbol - let sym = symbol_names::exported_name(ccx.shared(), instance); debug!("making {}", sym); // Create the global before evaluating the initializer; @@ -1043,9 +1043,8 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } hir_map::NodeForeignItem(&hir::ForeignItem { - ref attrs, name, span, node: hir::ForeignItemStatic(..), .. + ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let ident = imported_name(name, attrs); let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -1067,7 +1066,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = declare::declare_global(ccx, &ident, llty2); + let g1 = declare::declare_global(ccx, &sym, llty2); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -1077,10 +1076,10 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) // `extern_with_linkage_foo` will instead be initialized to // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(&ident); + real_name.push_str(&sym); let g2 = declare::define_global(ccx, &real_name, llty).unwrap_or_else(||{ ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", ident)) + &format!("symbol `{}` is already defined", sym)) }); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); @@ -1088,7 +1087,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } } else { // Generate an external declaration. - declare::declare_global(ccx, &ident, llty) + declare::declare_global(ccx, &sym, llty) }; for attr in attrs { @@ -1105,8 +1104,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } else { // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global - let name = symbol_names::exported_name(ccx.shared(), instance); - let g = declare::declare_global(ccx, &name, type_of::type_of(ccx, ty)); + let g = declare::declare_global(ccx, &sym, type_of::type_of(ccx, ty)); // Thread-local statics in some other crate need to *always* be linked // against in a thread-local fashion, so we need to be sure to apply the // thread-local attribute locally if it was present remotely. If we diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index e781468f96c9..b0f8edac0a62 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use back::symbol_names; use llvm::ValueRef; use llvm; use rustc::hir::def_id::DefId; @@ -88,7 +87,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, monomorphizing.insert(fn_id, depth + 1); } - let symbol = symbol_names::exported_name(ccx.shared(), instance); + let symbol = instance.symbol_name(ccx.shared()); debug!("monomorphize_fn mangled to {}", symbol); assert!(declare::get_defined_value(ccx, &symbol).is_none()); diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 6777e98d4b81..11e9e9f3204a 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -14,7 +14,6 @@ //! item-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. -use back::symbol_names; use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; use syntax::ast; @@ -53,7 +52,7 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names let instance = Instance::mono(self.ccx.shared(), def_id); - let name = symbol_names::exported_name(self.ccx.shared(), instance); + let name = instance.symbol_name(self.ccx.shared()); tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { let path = tcx.item_path_str(def_id); diff --git a/src/test/compile-fail/symbol-names/impl1.rs b/src/test/compile-fail/symbol-names/impl1.rs index 39bee26da20b..93fa48b880fd 100644 --- a/src/test/compile-fail/symbol-names/impl1.rs +++ b/src/test/compile-fail/symbol-names/impl1.rs @@ -25,7 +25,7 @@ mod bar { use foo::Foo; impl Foo { - #[rustc_symbol_name] //~ ERROR _ZN5impl13bar26_$LT$impl$u20$foo..Foo$GT$3baz + #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz #[rustc_item_path] //~ ERROR item-path(bar::::baz) fn baz() { } } From 07ce7f588a95093a6fcbe26feef4aba66759813d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 25 May 2016 01:45:25 +0300 Subject: [PATCH 130/179] trans: move the linker support to compute symbols on-demand. --- src/librustc_trans/back/link.rs | 13 ++-- src/librustc_trans/back/linker.rs | 116 ++++++++++++++++++++---------- src/librustc_trans/base.rs | 3 + src/librustc_trans/lib.rs | 1 + 4 files changed, 88 insertions(+), 45 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 53cc03198292..0a7c3b6fc8f4 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -9,7 +9,7 @@ // except according to those terms. use super::archive::{ArchiveBuilder, ArchiveConfig}; -use super::linker::{Linker, GnuLinker, MsvcLinker}; +use super::linker::Linker; use super::rpath::RPathConfig; use super::rpath; use super::msvc; @@ -637,13 +637,9 @@ fn link_natively(sess: &Session, } { - let mut linker = if sess.target.target.options.is_like_msvc { - Box::new(MsvcLinker { cmd: &mut cmd, sess: &sess }) as Box - } else { - Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box - }; + let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, - objects, out_filename, trans, outputs); + objects, out_filename, outputs); if !sess.target.target.options.no_compiler_rt { linker.link_staticlib("compiler-rt"); } @@ -712,7 +708,6 @@ fn link_args(cmd: &mut Linker, tmpdir: &Path, objects: &[PathBuf], out_filename: &Path, - trans: &CrateTranslation, outputs: &OutputFilenames) { // The default library location, we need this to find the runtime. @@ -731,7 +726,7 @@ fn link_args(cmd: &mut Linker, // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. if crate_type != config::CrateTypeExecutable { - cmd.export_symbols(sess, trans, tmpdir, crate_type); + cmd.export_symbols(tmpdir, crate_type); } // When linking a dynamic library, we put the metadata into a section of the diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 50f6366e85c8..cb990ead8e81 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -15,13 +15,50 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; +use context::SharedCrateContext; +use monomorphize::Instance; + use back::archive; use middle::dependency_format::Linkage; use session::Session; use session::config::CrateType; use session::config; use syntax::ast; -use CrateTranslation; + +/// For all the linkers we support, and information they might +/// need out of the shared crate context before we get rid of it. +pub struct LinkerInfo { + dylib_exports: Vec, + cdylib_exports: Vec +} + +impl<'a, 'tcx> LinkerInfo { + pub fn new(scx: &SharedCrateContext<'a, 'tcx>, + reachable: &[String]) -> LinkerInfo { + LinkerInfo { + dylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeDylib), + cdylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeCdylib) + } + } + + pub fn to_linker(&'a self, + cmd: &'a mut Command, + sess: &'a Session) -> Box { + if sess.target.target.options.is_like_msvc { + Box::new(MsvcLinker { + cmd: cmd, + sess: sess, + info: self + }) as Box + } else { + Box::new(GnuLinker { + cmd: cmd, + sess: sess, + info: self + }) as Box + } + } +} /// Linker abstraction used by back::link to build up the command to invoke a /// linker. @@ -53,16 +90,13 @@ pub trait Linker { fn hint_dynamic(&mut self); fn whole_archives(&mut self); fn no_whole_archives(&mut self); - fn export_symbols(&mut self, - sess: &Session, - trans: &CrateTranslation, - tmpdir: &Path, - crate_type: CrateType); + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); } pub struct GnuLinker<'a> { - pub cmd: &'a mut Command, - pub sess: &'a Session, + cmd: &'a mut Command, + sess: &'a Session, + info: &'a LinkerInfo } impl<'a> GnuLinker<'a> { @@ -201,11 +235,7 @@ impl<'a> Linker for GnuLinker<'a> { self.cmd.arg("-Wl,-Bdynamic"); } - fn export_symbols(&mut self, - sess: &Session, - trans: &CrateTranslation, - tmpdir: &Path, - crate_type: CrateType) { + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { // If we're compiling a dylib, then we let symbol visibility in object // files to take care of whether they're exported or not. // @@ -225,13 +255,13 @@ impl<'a> Linker for GnuLinker<'a> { }; let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); - for sym in exported_symbols(sess, trans, crate_type) { + for sym in &self.info.cdylib_exports { writeln!(f, "{}{}", prefix, sym)?; } Ok(()) })(); if let Err(e) = res { - sess.fatal(&format!("failed to write lib.def file: {}", e)); + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); } let mut arg = OsString::new(); if self.sess.target.target.options.is_like_osx { @@ -245,8 +275,9 @@ impl<'a> Linker for GnuLinker<'a> { } pub struct MsvcLinker<'a> { - pub cmd: &'a mut Command, - pub sess: &'a Session, + cmd: &'a mut Command, + sess: &'a Session, + info: &'a LinkerInfo } impl<'a> Linker for MsvcLinker<'a> { @@ -366,8 +397,6 @@ impl<'a> Linker for MsvcLinker<'a> { // in which case they may continue to transitively be used and hence need // their symbols exported. fn export_symbols(&mut self, - sess: &Session, - trans: &CrateTranslation, tmpdir: &Path, crate_type: CrateType) { let path = tmpdir.join("lib.def"); @@ -378,15 +407,18 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - - for sym in exported_symbols(sess, trans, crate_type) { - writeln!(f, " {}", sym)?; + let symbols = if crate_type == CrateType::CrateTypeCdylib { + &self.info.cdylib_exports + } else { + &self.info.dylib_exports + }; + for symbol in symbols { + writeln!(f, " {}", symbol)?; } - Ok(()) })(); if let Err(e) = res { - sess.fatal(&format!("failed to write lib.def file: {}", e)); + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); } let mut arg = OsString::from("/DEF:"); arg.push(path); @@ -394,10 +426,23 @@ impl<'a> Linker for MsvcLinker<'a> { } } -fn exported_symbols(sess: &Session, - trans: &CrateTranslation, - crate_type: CrateType) -> Vec { - let mut symbols = trans.reachable.iter().cloned().collect::>(); +fn exported_symbols(scx: &SharedCrateContext, + reachable: &[String], + crate_type: CrateType) + -> Vec { + if !scx.sess().crate_types.borrow().contains(&crate_type) { + return vec![]; + } + + // See explanation in GnuLinker::export_symbols, for + // why we don't ever need dylib symbols on non-MSVC. + if crate_type == CrateType::CrateTypeDylib { + if !scx.sess().target.target.options.is_like_msvc { + return vec![]; + } + } + + let mut symbols = reachable.to_vec(); // If we're producing anything other than a dylib then the `reachable` array // above is the exhaustive set of symbols we should be exporting. @@ -409,10 +454,10 @@ fn exported_symbols(sess: &Session, return symbols } - let cstore = &sess.cstore; - let formats = sess.dependency_formats.borrow(); - let upstream_symbols = formats[&crate_type].iter(); - symbols.extend(upstream_symbols.enumerate().filter_map(|(i, f)| { + let cstore = &scx.sess().cstore; + let formats = scx.sess().dependency_formats.borrow(); + let deps = formats[&crate_type].iter(); + symbols.extend(deps.enumerate().filter_map(|(i, f)| { if *f == Linkage::Static { Some((i + 1) as ast::CrateNum) } else { @@ -420,9 +465,8 @@ fn exported_symbols(sess: &Session, } }).flat_map(|cnum| { cstore.reachable_ids(cnum) - }).map(|did| { - cstore.item_symbol(did) + }).map(|did| -> String { + Instance::mono(scx, did).symbol_name(scx) })); - - return symbols + symbols } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 94ef80d3b858..84dd633a4526 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -31,6 +31,7 @@ use super::CrateTranslation; use super::ModuleTranslation; use back::link; +use back::linker::LinkerInfo; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; @@ -2828,6 +2829,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); + let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); CrateTranslation { modules: modules, metadata_module: metadata_module, @@ -2835,6 +2837,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: reachable_symbols, no_builtins: no_builtins, + linker_info: linker_info } } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index bccb5aa050b5..0188a6d54de2 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -145,6 +145,7 @@ pub struct CrateTranslation { pub metadata: Vec, pub reachable: Vec, pub no_builtins: bool, + pub linker_info: back::linker::LinkerInfo } __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } From e1cf4224466ff5eb54d318c4279f2c643fcf6ccd Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 12 May 2016 19:58:11 +0300 Subject: [PATCH 131/179] trans: remove item_symbols from metadata and CrateContext. --- src/librustc/middle/cstore.rs | 7 +------ src/librustc_metadata/common.rs | 2 +- src/librustc_metadata/csearch.rs | 11 +---------- src/librustc_metadata/decoder.rs | 8 -------- src/librustc_metadata/encoder.rs | 32 +------------------------------- src/librustc_trans/base.rs | 21 --------------------- src/librustc_trans/callee.rs | 5 ----- src/librustc_trans/consts.rs | 7 ++----- src/librustc_trans/context.rs | 10 ---------- 9 files changed, 6 insertions(+), 97 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 61978ca71d2f..3ede60beb744 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -34,8 +34,7 @@ use mir::mir_map::MirMap; use session::Session; use session::config::PanicStrategy; use session::search_paths::PathKind; -use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; -use std::cell::RefCell; +use util::nodemap::{FnvHashMap, NodeSet, DefIdMap}; use std::rc::Rc; use std::path::PathBuf; use syntax::ast; @@ -169,7 +168,6 @@ pub trait CrateStore<'tcx> { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; fn item_attrs(&self, def_id: DefId) -> Vec; - fn item_symbol(&self, def: DefId) -> String; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>; fn method_arg_names(&self, did: DefId) -> Vec; @@ -275,7 +273,6 @@ pub trait CrateStore<'tcx> { fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, - item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, mir_map: &MirMap<'tcx>, @@ -353,7 +350,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } - fn item_symbol(&self, def: DefId) -> String { bug!("item_symbol") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx> { bug!("trait_def") } fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> @@ -483,7 +479,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, - item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, mir_map: &MirMap<'tcx>, diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 2b972af07ff9..74f97de26589 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -33,7 +33,7 @@ pub const tag_items_data_item_family: usize = 0x24; pub const tag_items_data_item_type: usize = 0x25; -pub const tag_items_data_item_symbol: usize = 0x26; +// GAP 0x26 pub const tag_items_data_item_variant: usize = 0x27; diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 5d5820251491..5d42f8c1d6f6 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -25,7 +25,7 @@ use rustc::hir::map as hir_map; use rustc::hir::map::DefKey; use rustc::mir::repr::Mir; use rustc::mir::mir_map::MirMap; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{FnvHashMap, NodeSet, DefIdMap}; use rustc::session::config::PanicStrategy; use std::cell::RefCell; @@ -115,13 +115,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_item_attrs(&cdata, def_id.index) } - fn item_symbol(&self, def: DefId) -> String - { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_symbol(&cdata, def.index) - } - fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); @@ -569,7 +562,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, - item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, mir_map: &MirMap<'tcx>, @@ -579,7 +571,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { diag: tcx.sess.diagnostic(), tcx: tcx, reexports: reexports, - item_symbols: item_symbols, link_meta: link_meta, cstore: self, reachable: reachable, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 2c4edcea611d..d1153fe2d060 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -213,10 +213,6 @@ fn item_sort(item: rbml::Doc) -> Option { }) } -fn item_symbol(item: rbml::Doc) -> String { - reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() -} - fn untranslated_def_id(d: rbml::Doc) -> DefId { let id = reader::doc_as_u64(d); let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); @@ -640,10 +636,6 @@ pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd, } } -pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String { - return item_symbol(cdata.lookup_item(id)); -} - /// Iterates over the language items in the given crate. pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where F: FnMut(DefIndex, usize) -> bool, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 5476b21dd8c1..2bc953039adb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -34,7 +34,7 @@ use rustc::ty::util::IntTypeExt; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; use rustc::session::config::{self, PanicStrategy}; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; +use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::Encodable; use std::cell::RefCell; @@ -59,7 +59,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub reexports: &'a def::ExportMap, - pub item_symbols: &'a RefCell>, pub link_meta: &'a LinkMeta, pub cstore: &'a cstore::CStore, pub type_abbrevs: tyencode::abbrev_map<'tcx>, @@ -213,20 +212,6 @@ fn encode_region(ecx: &EncodeContext, rbml_w.end_tag(); } -fn encode_symbol(ecx: &EncodeContext, - rbml_w: &mut Encoder, - id: NodeId) { - match ecx.item_symbols.borrow().get(&id) { - Some(x) => { - debug!("encode_symbol(id={}, str={})", id, *x); - rbml_w.wr_tagged_str(tag_items_data_item_symbol, x); - } - None => { - bug!("encode_symbol: id not found {}", id); - } - } -} - fn encode_disr_val(_: &EncodeContext, rbml_w: &mut Encoder, disr_val: ty::Disr) { @@ -518,10 +503,6 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_name(rbml_w, name); encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); - if ecx.item_symbols.borrow().contains_key(&ctor_id) { - encode_symbol(ecx, rbml_w, ctor_id); - } - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); let depr= ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); encode_stability(rbml_w, stab); @@ -710,10 +691,6 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } encode_constness(rbml_w, sig.constness); encode_defaultness(rbml_w, impl_item.defaultness); - if !any_types { - let m_id = ecx.local_id(m.def_id); - encode_symbol(ecx, rbml_w, m_id); - } encode_method_argument_names(rbml_w, &sig.decl); } } @@ -894,7 +871,6 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_family(rbml_w, 'c'); } encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_symbol(ecx, rbml_w, item.id); encode_name(rbml_w, item.name); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); @@ -931,9 +907,6 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); encode_mir(ecx, rbml_w, item.id); } - if tps_len == 0 { - encode_symbol(ecx, rbml_w, item.id); - } encode_constness(rbml_w, constness); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); @@ -1365,8 +1338,6 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); encode_mir(ecx, rbml_w, nitem.id); - } else { - encode_symbol(ecx, rbml_w, nitem.id); } encode_attributes(rbml_w, &nitem.attrs); let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); @@ -1387,7 +1358,6 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); encode_stability(rbml_w, stab); encode_deprecation(rbml_w, depr); - encode_symbol(ecx, rbml_w, nitem.id); encode_name(rbml_w, nitem.name); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 84dd633a4526..c4afb348a0fa 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -38,7 +38,6 @@ use llvm; use rustc::cfg; use rustc::hir::def_id::DefId; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; -use middle::weak_lang_items; use rustc::hir::pat_util::simple_name; use rustc::ty::subst::{self, Substs}; use rustc::traits; @@ -2345,15 +2344,6 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { set_global_section(ccx, g, item); update_linkage(ccx, g, Some(item.id), OriginalTranslation); } - hir::ItemForeignMod(ref m) => { - if m.abi == Abi::RustIntrinsic || m.abi == Abi::PlatformIntrinsic { - return; - } - for fi in &m.items { - let lname = imported_name(fi.name, &fi.attrs).to_string(); - ccx.item_symbols().borrow_mut().insert(fi.id, lname); - } - } _ => {} } } @@ -2438,16 +2428,6 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { } } -pub fn imported_name(name: ast::Name, attrs: &[ast::Attribute]) -> InternedString { - match attr::first_attr_value_str_by_name(attrs, "link_name") { - Some(ln) => ln.clone(), - None => match weak_lang_items::link_name(attrs) { - Some(name) => name, - None => name.as_str(), - } - } -} - fn contains_null(s: &str) -> bool { s.bytes().any(|b| b == 0) } @@ -2471,7 +2451,6 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, let cstore = &cx.tcx().sess.cstore; let metadata = cstore.encode_metadata(cx.tcx(), cx.export_map(), - cx.item_symbols(), cx.link_meta(), reachable, mir_map, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index e7fa871d23db..d7f565a9cd44 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -575,11 +575,6 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn }; - // Always insert into item_symbols, in case this item is exported. - if let Some(id) = local_item { - ccx.item_symbols().borrow_mut().insert(id, sym); - } - ccx.instances().borrow_mut().insert(instance, llfn); immediate_rvalue(llfn, fn_ptr_ty) diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index bf7d1ef4d063..bd36c18a47ee 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1033,13 +1033,10 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) // Create the global before evaluating the initializer; // this is necessary to allow recursive statics. - let g = declare::define_global(ccx, &sym, llty).unwrap_or_else(|| { + declare::define_global(ccx, &sym, llty).unwrap_or_else(|| { ccx.sess().span_fatal(span, &format!("symbol `{}` is already defined", sym)) - }); - - ccx.item_symbols().borrow_mut().insert(id, sym); - g + }) } hir_map::NodeForeignItem(&hir::ForeignItem { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 95d56432e1e3..1c081bb49bca 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -71,7 +71,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { export_map: ExportMap, reachable: NodeSet, - item_symbols: RefCell>, link_meta: LinkMeta, symbol_hasher: RefCell, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -395,7 +394,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { metadata_llcx: metadata_llcx, export_map: export_map, reachable: reachable, - item_symbols: RefCell::new(NodeMap()), link_meta: link_meta, symbol_hasher: RefCell::new(symbol_hasher), tcx: tcx, @@ -439,10 +437,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.reachable } - pub fn item_symbols<'a>(&'a self) -> &'a RefCell> { - &self.item_symbols - } - pub fn trait_cache(&self) -> &RefCell>> { &self.trait_cache } @@ -720,10 +714,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.shared.reachable } - pub fn item_symbols<'a>(&'a self) -> &'a RefCell> { - &self.shared.item_symbols - } - pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { &self.shared.link_meta } From 2be9df79dd9d7554a5ec91ede3a07a3e8304f121 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Wed, 25 May 2016 10:09:20 +0800 Subject: [PATCH 132/179] Point out the clone operation in summary line docs of `Vec::extend_from_slice` --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 58d4a4ed4eb0..bd1bf6e9cc37 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -966,7 +966,7 @@ impl Vec { } } - /// Appends all elements in a slice to the `Vec`. + /// Clones and appends all elements in a slice to the `Vec`. /// /// Iterates over the slice `other`, clones each element, and then appends /// it to this `Vec`. The `other` vector is traversed in-order. From 12012cb70acf84fd4099959623af540bbf7675b7 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 25 May 2016 08:46:36 +0300 Subject: [PATCH 133/179] trans: save metadata even with -Z no-trans. --- src/librustc/session/config.rs | 2 +- src/librustc_driver/lib.rs | 4 -- src/librustc_trans/back/link.rs | 5 ++ src/librustc_trans/base.rs | 69 +++++++++++++++++----------- src/librustc_trans/context.rs | 4 ++ src/tools/compiletest/src/runtest.rs | 7 +++ 6 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index da5555dbd645..05ed02211097 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1104,7 +1104,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let no_analysis = debugging_opts.no_analysis; let mut output_types = HashMap::new(); - if !debugging_opts.parse_only && !no_trans { + if !debugging_opts.parse_only { for list in matches.opt_strs("emit") { for output_type in list.split(',') { let mut parts = output_type.splitn(2, '='); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 06133c508d9f..bd6b0599e783 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -511,10 +511,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_write_deps.stop = Compilation::Stop; } - if sess.opts.no_trans { - control.after_analysis.stop = Compilation::Stop; - } - if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) { control.after_llvm.stop = Compilation::Stop; } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 0a7c3b6fc8f4..4640377cf860 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -188,6 +188,11 @@ pub fn link_binary(sess: &Session, let mut out_filenames = Vec::new(); for &crate_type in sess.crate_types.borrow().iter() { + // Ignore executable crates if we have -Z no-trans, as they will error. + if sess.opts.no_trans && crate_type == config::CrateTypeExecutable { + continue; + } + if invalid_output_for_target(sess, crate_type) { bug!("invalid output type `{:?}` for target os `{}`", crate_type, sess.opts.target_triple); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c4afb348a0fa..03e12c1c8a7b 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2432,11 +2432,8 @@ fn contains_null(s: &str) -> bool { s.bytes().any(|b| b == 0) } -pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, - krate: &hir::Crate, - reachable: &NodeSet, - mir_map: &MirMap<'tcx>) - -> Vec { +fn write_metadata(cx: &SharedCrateContext, + reachable_ids: &NodeSet) -> Vec { use flate; let any_library = cx.sess() @@ -2452,9 +2449,9 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, let metadata = cstore.encode_metadata(cx.tcx(), cx.export_map(), cx.link_meta(), - reachable, - mir_map, - krate); + reachable_ids, + cx.mir_map(), + cx.tcx().map.krate()); let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); @@ -2639,10 +2636,12 @@ pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet { node: hir::ItemStatic(..), .. }) | hir_map::NodeItem(&hir::Item { node: hir::ItemFn(..), .. }) | - hir_map::NodeTraitItem(&hir::TraitItem { - node: hir::MethodTraitItem(_, Some(_)), .. }) | hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(..), .. }) => true, + node: hir::ImplItemKind::Method(..), .. }) => { + let def_id = scx.tcx().map.local_def_id(id); + let scheme = scx.tcx().lookup_item_type(def_id); + scheme.generics.types.is_empty() + } _ => false } @@ -2686,6 +2685,19 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_overflow, check_dropflag); + let reachable_symbol_ids = filter_reachable_ids(&shared_ccx); + + // Translate the metadata. + let metadata = time(tcx.sess.time_passes(), "write metadata", || { + write_metadata(&shared_ccx, &reachable_symbol_ids) + }); + + let metadata_module = ModuleTranslation { + llcx: shared_ccx.metadata_llcx(), + llmod: shared_ccx.metadata_llmod(), + }; + let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); + let codegen_units = collect_and_partition_translation_items(&shared_ccx); let codegen_unit_count = codegen_units.len(); assert!(tcx.sess.opts.cg.codegen_units == codegen_unit_count || @@ -2693,6 +2705,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units); + let modules = crate_context_list.iter() + .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() }) + .collect(); + + // Skip crate items and just output metadata in -Z no-trans mode. + if tcx.sess.opts.no_trans { + let linker_info = LinkerInfo::new(&shared_ccx, &[]); + return CrateTranslation { + modules: modules, + metadata_module: metadata_module, + link: link_meta, + metadata: metadata, + reachable: vec![], + no_builtins: no_builtins, + linker_info: linker_info + }; + } + { let ccx = crate_context_list.get_ccx(0); @@ -2722,13 +2752,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let reachable_symbol_ids = filter_reachable_ids(&shared_ccx); - - // Translate the metadata. - let metadata = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(&shared_ccx, krate, &reachable_symbol_ids, mir_map) - }); - if shared_ccx.sess().trans_stats() { let stats = shared_ccx.stats(); println!("--- trans stats ---"); @@ -2758,10 +2781,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let modules = crate_context_list.iter() - .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() }) - .collect(); - let sess = shared_ccx.sess(); let mut reachable_symbols = reachable_symbol_ids.iter().map(|&id| { let def_id = shared_ccx.tcx().map.local_def_id(id); @@ -2802,12 +2821,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, create_imps(&crate_context_list); } - let metadata_module = ModuleTranslation { - llcx: shared_ccx.metadata_llcx(), - llmod: shared_ccx.metadata_llmod(), - }; - let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); - let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); CrateTranslation { modules: modules, diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1c081bb49bca..1ddcbc79aed5 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -502,6 +502,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.symbol_hasher } + pub fn mir_map(&self) -> &MirMap<'tcx> { + &self.mir_map + } + pub fn metadata_symbol_name(&self) -> String { format!("rust_metadata_{}_{}", self.link_meta().crate_name, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e6dc3a9d360f..4040b55ff98c 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -371,9 +371,16 @@ actual:\n\ } else { &*self.config.target }; + + let out_dir = self.output_base_name().with_extension("pretty-out"); + let _ = fs::remove_dir_all(&out_dir); + self.create_dir_racy(&out_dir); + // FIXME (#9639): This needs to handle non-utf8 paths let mut args = vec!("-".to_owned(), "-Zno-trans".to_owned(), + "--out-dir".to_owned(), + out_dir.to_str().unwrap().to_owned(), format!("--target={}", target), "-L".to_owned(), self.config.build_base.to_str().unwrap().to_owned(), From b8aa7e5b7914d075e793a3bebf597d91395762cc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 25 May 2016 00:49:49 +0200 Subject: [PATCH 134/179] Implement Error trait for fmt::Error type --- src/libstd/error.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index d49d97649467..2a2d41112ffa 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -212,6 +212,13 @@ impl Error for Box { } } +#[stable(feature = "fmt_error", since = "1.11.0")] +impl Error for fmt::Error { + fn description(&self) -> &str { + "an error occurred when formatting an argument" + } +} + // copied from any.rs impl Error + 'static { /// Returns true if the boxed type is the same as `T` From 5e11d820bed3527cf906ef8813ad593864efb2ef Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 25 May 2016 13:40:35 +0200 Subject: [PATCH 135/179] Improve E0084 error explanation --- src/librustc_typeck/diagnostics.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 40b9b0e01ab9..b94c9c4ad19c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1193,12 +1193,32 @@ discriminant values so that they fit within the existing type. "##, E0084: r##" +An unsupported representation was attempted on a zero-variant enum. + +Erroneous code example: + +```compile_fail +#[repr(i32)] +enum NightWatch {} // error: unsupported representation for zero-variant enum +``` + It is impossible to define an integer type to be used to represent zero-variant enum values because there are no zero-variant enum values. There is no way to -construct an instance of the following type using only safe code: +construct an instance of the following type using only safe code. So you have +two solutions. Either you add variants in your enum: + +``` +#[repr(i32)] +enum NightWatch { + JohnSnow, + Commander, +} +``` + +or you remove the integer represention of your enum: ``` -enum Empty {} +enum NightWatch {} ``` "##, From 2855a21eae955fe247ebfc06f1a2f1b403ce7b94 Mon Sep 17 00:00:00 2001 From: ggomez Date: Wed, 25 May 2016 13:58:07 +0200 Subject: [PATCH 136/179] Add new error code tests --- src/test/compile-fail/E0084.rs | 15 +++++++++++++++ src/test/compile-fail/E0087.rs | 15 +++++++++++++++ src/test/compile-fail/E0088.rs | 15 +++++++++++++++ src/test/compile-fail/E0089.rs | 15 +++++++++++++++ src/test/compile-fail/E0091.rs | 15 +++++++++++++++ src/test/compile-fail/E0092.rs | 17 +++++++++++++++++ src/test/compile-fail/E0093.rs | 17 +++++++++++++++++ src/test/compile-fail/E0094.rs | 17 +++++++++++++++++ src/test/compile-fail/E0101.rs | 13 +++++++++++++ src/test/compile-fail/E0102.rs | 13 +++++++++++++ src/test/compile-fail/E0106.rs | 21 +++++++++++++++++++++ src/test/compile-fail/E0107.rs | 25 +++++++++++++++++++++++++ src/test/compile-fail/E0109.rs | 14 ++++++++++++++ src/test/compile-fail/E0110.rs | 14 ++++++++++++++ src/test/compile-fail/E0116.rs | 14 ++++++++++++++ 15 files changed, 240 insertions(+) create mode 100644 src/test/compile-fail/E0084.rs create mode 100644 src/test/compile-fail/E0087.rs create mode 100644 src/test/compile-fail/E0088.rs create mode 100644 src/test/compile-fail/E0089.rs create mode 100644 src/test/compile-fail/E0091.rs create mode 100644 src/test/compile-fail/E0092.rs create mode 100644 src/test/compile-fail/E0093.rs create mode 100644 src/test/compile-fail/E0094.rs create mode 100644 src/test/compile-fail/E0101.rs create mode 100644 src/test/compile-fail/E0102.rs create mode 100644 src/test/compile-fail/E0106.rs create mode 100644 src/test/compile-fail/E0107.rs create mode 100644 src/test/compile-fail/E0109.rs create mode 100644 src/test/compile-fail/E0110.rs create mode 100644 src/test/compile-fail/E0116.rs diff --git a/src/test/compile-fail/E0084.rs b/src/test/compile-fail/E0084.rs new file mode 100644 index 000000000000..c579101325f5 --- /dev/null +++ b/src/test/compile-fail/E0084.rs @@ -0,0 +1,15 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(i32)] +enum Foo {} //~ ERROR E0084 + +fn main() { +} diff --git a/src/test/compile-fail/E0087.rs b/src/test/compile-fail/E0087.rs new file mode 100644 index 000000000000..ec559fc8389d --- /dev/null +++ b/src/test/compile-fail/E0087.rs @@ -0,0 +1,15 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() {} + +fn main() { + foo::(); //~ ERROR E0087 +} diff --git a/src/test/compile-fail/E0088.rs b/src/test/compile-fail/E0088.rs new file mode 100644 index 000000000000..0b235aa240c3 --- /dev/null +++ b/src/test/compile-fail/E0088.rs @@ -0,0 +1,15 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f() {} + +fn main() { + f::<'static>(); //~ ERROR E0088 +} diff --git a/src/test/compile-fail/E0089.rs b/src/test/compile-fail/E0089.rs new file mode 100644 index 000000000000..3b52f76bf09c --- /dev/null +++ b/src/test/compile-fail/E0089.rs @@ -0,0 +1,15 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() {} + +fn main() { + foo::(); //~ ERROR E0089 +} diff --git a/src/test/compile-fail/E0091.rs b/src/test/compile-fail/E0091.rs new file mode 100644 index 000000000000..da988dbf819a --- /dev/null +++ b/src/test/compile-fail/E0091.rs @@ -0,0 +1,15 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type Foo = u32; //~ ERROR E0091 +type Foo2 = Box; //~ ERROR E0091 + +fn main() { +} diff --git a/src/test/compile-fail/E0092.rs b/src/test/compile-fail/E0092.rs new file mode 100644 index 000000000000..b08164ac06d4 --- /dev/null +++ b/src/test/compile-fail/E0092.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] +extern "rust-intrinsic" { + fn atomic_foo(); //~ ERROR E0092 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0093.rs b/src/test/compile-fail/E0093.rs new file mode 100644 index 000000000000..9b23f6d984ee --- /dev/null +++ b/src/test/compile-fail/E0093.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] +extern "rust-intrinsic" { + fn foo(); //~ ERROR E0093 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0094.rs b/src/test/compile-fail/E0094.rs new file mode 100644 index 000000000000..3a31874b2442 --- /dev/null +++ b/src/test/compile-fail/E0094.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] +extern "rust-intrinsic" { + fn size_of() -> usize; //~ ERROR E0094 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0101.rs b/src/test/compile-fail/E0101.rs new file mode 100644 index 000000000000..7651626d44f8 --- /dev/null +++ b/src/test/compile-fail/E0101.rs @@ -0,0 +1,13 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = |_| {}; //~ ERROR E0101 +} diff --git a/src/test/compile-fail/E0102.rs b/src/test/compile-fail/E0102.rs new file mode 100644 index 000000000000..c4ddbab3e861 --- /dev/null +++ b/src/test/compile-fail/E0102.rs @@ -0,0 +1,13 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = []; //~ ERROR E0102 +} diff --git a/src/test/compile-fail/E0106.rs b/src/test/compile-fail/E0106.rs new file mode 100644 index 000000000000..f1cd530863d3 --- /dev/null +++ b/src/test/compile-fail/E0106.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + x: &bool, //~ ERROR E0106 +} +enum Bar { + A(u8), + B(&bool), //~ ERROR E0106 +} +type MyStr = &str; //~ ERROR E0106 + +fn main() { +} diff --git a/src/test/compile-fail/E0107.rs b/src/test/compile-fail/E0107.rs new file mode 100644 index 000000000000..d27b70865bbf --- /dev/null +++ b/src/test/compile-fail/E0107.rs @@ -0,0 +1,25 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo<'a>(&'a str); + +enum Bar { + A, + B, + C, +} + +struct Baz<'a> { + foo: Foo, //~ ERROR E0107 + bar: Bar<'a>, //~ ERROR E0107 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0109.rs b/src/test/compile-fail/E0109.rs new file mode 100644 index 000000000000..9fc478422504 --- /dev/null +++ b/src/test/compile-fail/E0109.rs @@ -0,0 +1,14 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type X = u32; //~ ERROR E0109 + +fn main() { +} diff --git a/src/test/compile-fail/E0110.rs b/src/test/compile-fail/E0110.rs new file mode 100644 index 000000000000..fd169f4acc5e --- /dev/null +++ b/src/test/compile-fail/E0110.rs @@ -0,0 +1,14 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type X = u32<'static>; //~ ERROR E0110 + +fn main() { +} diff --git a/src/test/compile-fail/E0116.rs b/src/test/compile-fail/E0116.rs new file mode 100644 index 000000000000..4020aa9475aa --- /dev/null +++ b/src/test/compile-fail/E0116.rs @@ -0,0 +1,14 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +impl Vec {} //~ ERROR E0116 + +fn main() { +} From 06174e69bc577d8b8459c02b23df14857d3e7b91 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 May 2016 14:52:40 +0200 Subject: [PATCH 137/179] Fix some comments. --- .../borrowck/mir/dataflow/mod.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index dad0c9251860..da7a85c1a8a6 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -324,9 +324,9 @@ pub trait BitDenotation { /// "transfer-function" represnting the overall-effect of the /// block, represented via GEN and KILL sets. /// - /// The statement here is `idx_stmt.1`; `idx_stmt.0` is just - /// an identifying index: namely, the index of the statement - /// in the basic block. + /// The statement is identified as `bb_data[idx_stmt]`, where + /// `bb_data` is the sequence of statements identifed by `bb` in + /// the MIR. fn statement_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, @@ -341,10 +341,6 @@ pub trait BitDenotation { /// "transfer-function" represnting the overall-effect of the /// block, represented via GEN and KILL sets. /// - /// The terminator here is `idx_term.1`; `idx_term.0` is just an - /// identifying index: namely, the number of statements in `bb` - /// itself. - /// /// The effects applied here cannot depend on which branch the /// terminator took. fn terminator_effect(&self, @@ -367,6 +363,11 @@ pub trait BitDenotation { /// flow-dependent, the current MIR cannot encode them via just /// GEN and KILL sets attached to the block, and so instead we add /// this extra machinery to represent the flow-dependent effect. + /// + /// FIXME: Right now this is a bit of a wart in the API. It might + /// be better to represent this as an additional gen- and + /// kill-sets associated with each edge coming out of the basic + /// block. fn propagate_call_return(&self, ctxt: &Self::Ctxt, in_out: &mut IdxSet, From c19958cada17d734286364d61abf60823a6c07f4 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 May 2016 14:54:31 +0200 Subject: [PATCH 138/179] Add notes that data-structures should potentially move to different crate. --- src/librustc_borrowck/bitslice.rs | 3 +++ src/librustc_borrowck/indexed_set.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_borrowck/bitslice.rs index 7a203b7f0b71..80fa86a007ed 100644 --- a/src/librustc_borrowck/bitslice.rs +++ b/src/librustc_borrowck/bitslice.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME: move this to `rustc_data_structures` and potentially merge +// with `bitvec` there. + use std::mem; pub type Word = usize; diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs index bf5eb10b8ed5..feb01c635602 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_borrowck/indexed_set.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME: move this to `rustc_data_structures` + use std::fmt; use std::marker::PhantomData; use std::mem; From 78c4f262ed187a2f98a8ffa7c265f5a89f62d812 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 May 2016 15:41:49 +0200 Subject: [PATCH 139/179] remove unnecessary use of `indexed_set::Indexed` trait. --- src/librustc_borrowck/borrowck/mir/gather_moves.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 45fb98df6530..48511cd5ebc9 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -20,7 +20,7 @@ use std::iter; use std::ops::Index; use super::abs_domain::{AbstractElem, Lift}; -use indexed_set::{Idx, Indexed}; +use indexed_set::{Idx}; // This submodule holds some newtype'd Index wrappers that are using // NonZero to ensure that Option occupies only a single word. @@ -60,14 +60,6 @@ mod indexes { pub use self::indexes::MovePathIndex; pub use self::indexes::MoveOutIndex; -impl<'tcx> Indexed for MovePath<'tcx> { - type Idx = MovePathIndex; -} - -impl Indexed for MoveOut { - type Idx = MoveOutIndex; -} - impl self::indexes::MoveOutIndex { pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex { move_data.moves[self.idx()].path From ca5975beb73ece40dd719c2cbb43d5ba743a0c44 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 May 2016 15:41:57 +0200 Subject: [PATCH 140/179] remove `indexed_set::Indexed` trait. --- src/librustc_borrowck/indexed_set.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs index feb01c635602..5e842c1c5aba 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_borrowck/indexed_set.rs @@ -17,10 +17,6 @@ use std::ops::{Deref, DerefMut, Range}; use bitslice::{BitSlice, Word}; use bitslice::{bitwise, Union, Subtract}; -pub trait Indexed { - type Idx: Idx; -} - pub trait Idx: 'static { fn new(usize) -> Self; fn idx(&self) -> usize; From 43692d354ad32409d1a3aeda7b11a005fe26d06a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 May 2016 15:53:59 +0200 Subject: [PATCH 141/179] fixes to `indexed_set`: add comments and fix `PhantomData` def'n. --- src/librustc_borrowck/indexed_set.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs index 5e842c1c5aba..2625bd4300c2 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_borrowck/indexed_set.rs @@ -17,13 +17,21 @@ use std::ops::{Deref, DerefMut, Range}; use bitslice::{BitSlice, Word}; use bitslice::{bitwise, Union, Subtract}; +/// Represents some newtyped `usize` wrapper. +/// +/// (purpose: avoid mixing indexes for different bitvector domains.) pub trait Idx: 'static { fn new(usize) -> Self; fn idx(&self) -> usize; } +/// Represents a set (or packed family of sets), of some element type +/// E, where each E is identified by some unique index type `T`. +/// +/// In other words, `T` is the type used to index into the bitvector +/// this type uses to represent the set of object it holds. pub struct OwnIdxSet { - _pd: PhantomData &T>, + _pd: PhantomData, bits: Vec, } @@ -40,8 +48,13 @@ impl Clone for OwnIdxSet { // requires a transmute relying on representation guarantees that may // not hold in the future. +/// Represents a set (or packed family of sets), of some element type +/// E, where each E is identified by some unique index type `T`. +/// +/// In other words, `T` is the type used to index into the bitslice +/// this type uses to represent the set of object it holds. pub struct IdxSet { - _pd: PhantomData &T>, + _pd: PhantomData, bits: [Word], } From f105218eea9567805a254e3129d5332124f9a56a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 May 2016 15:55:46 +0200 Subject: [PATCH 142/179] Alpha rename `OwnIdxSet` to `IdxSetBuf`. --- .../borrowck/mir/dataflow/mod.rs | 14 ++++++------ src/librustc_borrowck/indexed_set.rs | 22 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index da7a85c1a8a6..b46b6c368a05 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -21,7 +21,7 @@ use super::MirBorrowckCtxtPreDataflow; use super::MoveDataParamEnv; use bitslice::{bitwise, BitwiseOperator}; -use indexed_set::{Idx, IdxSet, OwnIdxSet}; +use indexed_set::{Idx, IdxSet, IdxSetBuf}; pub use self::sanity_check::sanity_check_via_rustc_peek; pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals}; @@ -57,7 +57,7 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation + DataflowOperator { fn propagate(&mut self) { - let mut temp = OwnIdxSet::new_empty(self.flow_state.sets.bits_per_block); + let mut temp = IdxSetBuf::new_empty(self.flow_state.sets.bits_per_block); let mut propcx = PropagationContext { builder: self, changed: true, @@ -167,7 +167,7 @@ impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD> /// Maps each block to a set of bits #[derive(Debug)] struct Bits { - bits: OwnIdxSet, + bits: IdxSetBuf, } impl Clone for Bits { @@ -175,7 +175,7 @@ impl Clone for Bits { } impl Bits { - fn new(bits: OwnIdxSet) -> Self { + fn new(bits: IdxSetBuf) -> Self { Bits { bits: bits } } } @@ -393,11 +393,11 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> let num_blocks = mir.basic_blocks.len(); let num_overall = num_blocks * bits_per_block; - let zeroes = Bits::new(OwnIdxSet::new_empty(num_overall)); + let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall)); let on_entry = Bits::new(if D::bottom_value() { - OwnIdxSet::new_filled(num_overall) + IdxSetBuf::new_filled(num_overall) } else { - OwnIdxSet::new_empty(num_overall) + IdxSetBuf::new_empty(num_overall) }); DataflowAnalysis { diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs index 2625bd4300c2..3fee1dbc0566 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_borrowck/indexed_set.rs @@ -30,21 +30,21 @@ pub trait Idx: 'static { /// /// In other words, `T` is the type used to index into the bitvector /// this type uses to represent the set of object it holds. -pub struct OwnIdxSet { +pub struct IdxSetBuf { _pd: PhantomData, bits: Vec, } -impl Clone for OwnIdxSet { +impl Clone for IdxSetBuf { fn clone(&self) -> Self { - OwnIdxSet { _pd: PhantomData, bits: self.bits.clone() } + IdxSetBuf { _pd: PhantomData, bits: self.bits.clone() } } } // pnkfelix wants to have this be `IdxSet([Word]) and then pass // around `&mut IdxSet` or `&IdxSet`. // -// WARNING: Mapping a `&OwnIdxSet` to `&IdxSet` (at least today) +// WARNING: Mapping a `&IdxSetBuf` to `&IdxSet` (at least today) // requires a transmute relying on representation guarantees that may // not hold in the future. @@ -58,7 +58,7 @@ pub struct IdxSet { bits: [Word], } -impl fmt::Debug for OwnIdxSet { +impl fmt::Debug for IdxSetBuf { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) } } @@ -66,11 +66,11 @@ impl fmt::Debug for IdxSet { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) } } -impl OwnIdxSet { +impl IdxSetBuf { fn new(init: Word, universe_size: usize) -> Self { let bits_per_word = mem::size_of::() * 8; let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word; - OwnIdxSet { + IdxSetBuf { _pd: Default::default(), bits: vec![init; num_words], } @@ -97,22 +97,22 @@ impl IdxSet { } } -impl Deref for OwnIdxSet { +impl Deref for IdxSetBuf { type Target = IdxSet; fn deref(&self) -> &IdxSet { unsafe { IdxSet::from_slice(&self.bits[..]) } } } -impl DerefMut for OwnIdxSet { +impl DerefMut for IdxSetBuf { fn deref_mut(&mut self) -> &mut IdxSet { unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) } } } impl IdxSet { - pub fn to_owned(&self) -> OwnIdxSet { - OwnIdxSet { + pub fn to_owned(&self) -> IdxSetBuf { + IdxSetBuf { _pd: Default::default(), bits: self.bits.to_owned(), } From 2760be405ddaf2e8c89544881a2c8fb10b48e525 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 25 May 2016 21:12:35 +0300 Subject: [PATCH 143/179] catch attempts to leak obligations out of snapshots --- src/librustc/infer/mod.rs | 33 ++++- src/librustc/traits/fulfill.rs | 2 + src/librustc/traits/specialize/mod.rs | 82 ++++++------ src/librustc_typeck/check/coercion.rs | 2 + src/librustc_typeck/check/compare_method.rs | 119 ++++++++---------- .../regions-bound-missing-bound-in-impl.rs | 3 +- src/test/compile-fail/regions-trait-1.rs | 2 +- 7 files changed, 127 insertions(+), 116 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 41982ddc78b6..7c9c52baa63e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -163,6 +163,11 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // If the number of errors increases, that's also a sign (line // `tained_by_errors`) to avoid reporting certain kinds of errors. err_count_on_creation: usize, + + // This flag is used for debugging, and is set to true if there are + // any obligations set during the current snapshot. In that case, the + // snapshot can't be rolled back. + pub obligations_in_snapshot: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -476,7 +481,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { normalize: false, projection_mode: ProjectionMode::AnyFinal, tainted_by_errors_flag: Cell::new(false), - err_count_on_creation: self.sess.err_count() + err_count_on_creation: self.sess.err_count(), + obligations_in_snapshot: Cell::new(false), } } } @@ -515,7 +521,8 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { normalize: normalize, projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), - err_count_on_creation: tcx.sess.err_count() + err_count_on_creation: tcx.sess.err_count(), + obligations_in_snapshot: Cell::new(false), })) } } @@ -542,6 +549,7 @@ pub struct CombinedSnapshot { int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_vars_snapshot: RegionSnapshot, + obligations_in_snapshot: bool, } /// Helper trait for shortening the lifetimes inside a @@ -809,11 +817,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn start_snapshot(&self) -> CombinedSnapshot { + let obligations_in_snapshot = self.obligations_in_snapshot.get(); + self.obligations_in_snapshot.set(false); + CombinedSnapshot { type_snapshot: self.type_variables.borrow_mut().snapshot(), int_snapshot: self.int_unification_table.borrow_mut().snapshot(), float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_vars_snapshot: self.region_vars.start_snapshot(), + obligations_in_snapshot: obligations_in_snapshot, } } @@ -822,7 +834,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let CombinedSnapshot { type_snapshot, int_snapshot, float_snapshot, - region_vars_snapshot } = snapshot; + region_vars_snapshot, + obligations_in_snapshot } = snapshot; + + assert!(!self.obligations_in_snapshot.get()); + self.obligations_in_snapshot.set(obligations_in_snapshot); self.type_variables .borrow_mut() @@ -842,7 +858,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let CombinedSnapshot { type_snapshot, int_snapshot, float_snapshot, - region_vars_snapshot } = snapshot; + region_vars_snapshot, + obligations_in_snapshot } = snapshot; + + self.obligations_in_snapshot.set(obligations_in_snapshot); self.type_variables .borrow_mut() @@ -904,12 +923,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let CombinedSnapshot { type_snapshot, int_snapshot, float_snapshot, - region_vars_snapshot } = self.start_snapshot(); + region_vars_snapshot, + obligations_in_snapshot } = self.start_snapshot(); let r = self.commit_if_ok(|_| f()); debug!("commit_regions_if_ok: rolling back everything but regions"); + assert!(!self.obligations_in_snapshot.get()); + self.obligations_in_snapshot.set(obligations_in_snapshot); + // Roll back any non-region bindings - they should be resolved // inside `f`, with, e.g. `resolve_type_vars_if_possible`. self.type_variables diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index d9d0367bdcb1..0d7d7afd120d 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -171,6 +171,8 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { // debug output much nicer to read and so on. let obligation = infcx.resolve_type_vars_if_possible(&obligation); + infcx.obligations_in_snapshot.set(true); + if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { return diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index b2d14dab9a0b..c7a363755760 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -187,51 +187,49 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, source_trait_ref: ty::TraitRef<'tcx>, target_impl: DefId) -> Result<&'tcx Substs<'tcx>, ()> { - infcx.commit_if_ok(|_| { - let selcx = &mut SelectionContext::new(&infcx); - let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl); - let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, - target_impl, - &target_substs); - - // do the impls unify? If not, no specialization. - if let Err(_) = infcx.eq_trait_refs(true, - TypeOrigin::Misc(DUMMY_SP), - source_trait_ref, - target_trait_ref) { - debug!("fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, - target_trait_ref); - return Err(()); - } + let selcx = &mut SelectionContext::new(&infcx); + let target_substs = fresh_type_vars_for_impl(&infcx, DUMMY_SP, target_impl); + let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, + target_impl, + &target_substs); + + // do the impls unify? If not, no specialization. + if let Err(_) = infcx.eq_trait_refs(true, + TypeOrigin::Misc(DUMMY_SP), + source_trait_ref, + target_trait_ref) { + debug!("fulfill_implication: {:?} does not unify with {:?}", + source_trait_ref, + target_trait_ref); + return Err(()); + } - // attempt to prove all of the predicates for impl2 given those for impl1 - // (which are packed up in penv) + // attempt to prove all of the predicates for impl2 given those for impl1 + // (which are packed up in penv) - let mut fulfill_cx = FulfillmentContext::new(); - for oblig in obligations.into_iter() { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } + let mut fulfill_cx = FulfillmentContext::new(); + for oblig in obligations.into_iter() { + fulfill_cx.register_predicate_obligation(&infcx, oblig); + } - if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) { - // no dice! - debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ - {:?}", - source_trait_ref, - target_trait_ref, - errors, - infcx.parameter_environment.caller_bounds); - Err(()) - } else { - debug!("fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, - target_trait_ref); - - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_type_vars_if_possible(&target_substs)) - } - }) + if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) { + // no dice! + debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ + {:?}", + source_trait_ref, + target_trait_ref, + errors, + infcx.parameter_environment.caller_bounds); + Err(()) + } else { + debug!("fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, + target_trait_ref); + + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + } } pub struct SpecializesCache { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 2225fd588b1c..9dd737f3a616 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -363,6 +363,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; + // This commits the obligations to the fulfillcx. After this succeeds, + // this snapshot can't be rolled back. autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs()); // Now apply the autoref. We have to extract the region out of diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index a1a6a83d34ff..20f82271b9cd 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -279,78 +279,63 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // type. // Compute skolemized form of impl and trait method tys. - let impl_fty = tcx.mk_fn_ptr(impl_m.fty); - let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs); - let trait_fty = tcx.mk_fn_ptr(trait_m.fty); - let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); - - let err = infcx.commit_if_ok(|snapshot| { - let tcx = infcx.tcx; - let origin = TypeOrigin::MethodCompatCheck(impl_m_span); - - let (impl_sig, _) = - infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, - infer::HigherRankedType, - &impl_m.fty.sig); - let impl_sig = - impl_sig.subst(tcx, impl_to_skol_substs); - let impl_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_m_span, - impl_m_body_id, - &impl_sig); - let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: impl_m.fty.unsafety, - abi: impl_m.fty.abi, - sig: ty::Binder(impl_sig) - })); - debug!("compare_impl_method: impl_fty={:?}", - impl_fty); - - let (trait_sig, skol_map) = - infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot); - let trait_sig = - trait_sig.subst(tcx, &trait_to_skol_substs); - let trait_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_m_span, - impl_m_body_id, - &trait_sig); - let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: trait_m.fty.unsafety, - abi: trait_m.fty.abi, - sig: ty::Binder(trait_sig) - })); - - debug!("compare_impl_method: trait_fty={:?}", + let tcx = infcx.tcx; + let origin = TypeOrigin::MethodCompatCheck(impl_m_span); + + let (impl_sig, _) = + infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, + infer::HigherRankedType, + &impl_m.fty.sig); + let impl_sig = + impl_sig.subst(tcx, impl_to_skol_substs); + let impl_sig = + assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx, + impl_m_span, + impl_m_body_id, + &impl_sig); + let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: impl_m.fty.unsafety, + abi: impl_m.fty.abi, + sig: ty::Binder(impl_sig) + })); + debug!("compare_impl_method: impl_fty={:?}", impl_fty); + + let trait_sig = tcx.liberate_late_bound_regions( + infcx.parameter_environment.free_id_outlive, + &trait_m.fty.sig); + let trait_sig = + trait_sig.subst(tcx, &trait_to_skol_substs); + let trait_sig = + assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx, + impl_m_span, + impl_m_body_id, + &trait_sig); + let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { + unsafety: trait_m.fty.unsafety, + abi: trait_m.fty.abi, + sig: ty::Binder(trait_sig) + })); + + debug!("compare_impl_method: trait_fty={:?}", trait_fty); + + if let Err(terr) = infcx.sub_types(false, origin, impl_fty, trait_fty) { + debug!("sub_types failed: impl ty {:?}, trait ty {:?}", + impl_fty, trait_fty); - - infcx.sub_types(false, origin, impl_fty, trait_fty)?; - - infcx.leak_check(false, &skol_map, snapshot) - }); - - match err { - Ok(()) => { } - Err(terr) => { - debug!("checking trait method for compatibility: impl ty {:?}, trait ty {:?}", - impl_fty, - trait_fty); - span_err!(tcx.sess, impl_m_span, E0053, - "method `{}` has an incompatible type for trait: {}", - trait_m.name, - terr); - return; - } + span_err!(tcx.sess, impl_m_span, E0053, + "method `{}` has an incompatible type for trait: {}", + trait_m.name, + terr); + return } // Check that all obligations are satisfied by the implementation's // version. - match fulfillment_cx.select_all_or_error(&infcx) { - Err(ref errors) => { infcx.report_fulfillment_errors(errors) } - Ok(_) => {} + if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(errors); + return } // Finally, resolve all regions. This catches wily misuses of diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs index abffd33e3f83..6e60a373d9b0 100644 --- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs +++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs @@ -34,7 +34,8 @@ impl<'a, 't> Foo<'a, 't> for &'a isize { } fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { - //~^ ERROR method `wrong_bound1` has an incompatible type for trait + //~^ ERROR method not compatible with trait + //~^^ ERROR method not compatible with trait // // Note: This is a terrible error message. It is caused // because, in the trait, 'b is early bound, and in the impl, diff --git a/src/test/compile-fail/regions-trait-1.rs b/src/test/compile-fail/regions-trait-1.rs index 01439ce5e687..9cd08656b62c 100644 --- a/src/test/compile-fail/regions-trait-1.rs +++ b/src/test/compile-fail/regions-trait-1.rs @@ -23,7 +23,7 @@ impl<'a> get_ctxt for has_ctxt<'a> { // Here an error occurs because we used `&self` but // the definition used `&`: - fn get_ctxt(&self) -> &'a ctxt { //~ ERROR method `get_ctxt` has an incompatible type + fn get_ctxt(&self) -> &'a ctxt { //~ ERROR method not compatible with trait self.c } From 07696af1558da54ebecea6a3e82911a44f27aa9e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 144/179] Remove ExplicitSelf from AST --- src/librustc/hir/lowering.rs | 6 +- src/librustc/hir/mod.rs | 3 + src/librustc/lint/context.rs | 5 - src/librustc/lint/mod.rs | 2 - src/librustc_resolve/build_reduced_graph.rs | 4 +- src/librustc_typeck/astconv.rs | 3 +- src/libsyntax/ast.rs | 84 +++++++------- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/fold.rs | 32 +----- src/libsyntax/parse/parser.rs | 118 ++++++++++---------- src/libsyntax/print/pprust.rs | 78 +++++-------- src/libsyntax/util/node_count.rs | 4 - src/libsyntax/visit.rs | 23 ---- src/libsyntax_ext/deriving/generic/mod.rs | 42 +++---- src/libsyntax_ext/deriving/generic/ty.rs | 10 +- 15 files changed, 155 insertions(+), 261 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 56777dc41d71..ac6c9ad64f3a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -792,10 +792,10 @@ impl<'a> LoweringContext<'a> { fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig { // Check for `self: _` and `self: &_` - if let SelfKind::Explicit(ref ty, _) = sig.explicit_self.node { - match sig.decl.inputs.get(0).and_then(Arg::to_self).map(|eself| eself.node) { + if !sig.self_shortcut { + match sig.decl.get_self().map(|eself| eself.node) { Some(SelfKind::Value(..)) | Some(SelfKind::Region(..)) => { - self.id_assigner.diagnostic().span_err(ty.span, + self.id_assigner.diagnostic().span_err(sig.decl.inputs[0].ty.span, "the type placeholder `_` is not allowed within types on item signatures"); } _ => {} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index b147782316fd..faff8446afcc 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1175,6 +1175,9 @@ pub struct FnDecl { } impl FnDecl { + pub fn get_self(&self) -> Option { + self.inputs.get(0).and_then(Arg::to_self) + } pub fn has_self(&self) -> bool { self.inputs.get(0).map(Arg::is_self).unwrap_or(false) } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 0801f8f4ac7e..94f17ea779ac 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1043,11 +1043,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { run_lints!(self, check_lifetime_def, early_passes, lt); } - fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) { - run_lints!(self, check_explicit_self, early_passes, es); - ast_visit::walk_explicit_self(self, es); - } - fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) { run_lints!(self, check_path, early_passes, p, id); ast_visit::walk_path(self, p); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 28994e1a7c48..cc7fa54bd0a5 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -167,7 +167,6 @@ pub trait LateLintPass: LintPass { fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } fn check_lifetime(&mut self, _: &LateContext, _: &hir::Lifetime) { } fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { } - fn check_explicit_self(&mut self, _: &LateContext, _: &hir::ExplicitSelf) { } fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { } fn check_path_list_item(&mut self, _: &LateContext, _: &hir::PathListItem) { } fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { } @@ -218,7 +217,6 @@ pub trait EarlyLintPass: LintPass { fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { } fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { } - fn check_explicit_self(&mut self, _: &EarlyContext, _: &ast::ExplicitSelf) { } fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { } fn check_path_list_item(&mut self, _: &EarlyContext, _: &ast::PathListItem) { } fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f56b22f92489..e0243bf4fa69 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -35,7 +35,7 @@ use syntax::codemap::{Span, DUMMY_SP}; use syntax::ast::{Block, Crate, DeclKind}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, PathListItemKind}; -use syntax::ast::{SelfKind, Stmt, StmtKind, TraitItemKind}; +use syntax::ast::{Stmt, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::visit::{self, Visitor}; @@ -335,7 +335,7 @@ impl<'b> Resolver<'b> { let (def, ns) = match item.node { TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS), TraitItemKind::Method(ref sig, _) => { - is_static_method = sig.explicit_self.node == SelfKind::Static; + is_static_method = !sig.decl.has_self(); (Def::Method(item_def_id), ValueNS) } TraitItemKind::Type(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1df12b63e0a5..fc1abb56d5ab 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1833,8 +1833,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // lifetime elision, we can determine it in two ways. First (determined // here), if self is by-reference, then the implied output region is the // region of the self parameter. - let explicit_self = decl.inputs.get(0).and_then(hir::Arg::to_self); - let (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, explicit_self) { + let (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, decl.get_self()) { (Some(untransformed_self_ty), Some(explicit_self)) => { let self_type = self.determine_self_type(&rb, untransformed_self_ty, &explicit_self); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4a94d8b01a34..9c87fda62833 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1387,7 +1387,8 @@ pub struct MethodSig { pub abi: Abi, pub decl: P, pub generics: Generics, - pub explicit_self: ExplicitSelf, + /// A short form of self argument was used (`self`, `&self` etc, but not `self: TYPE`). + pub self_shortcut: bool, } /// Represents an item declaration within a trait declaration, @@ -1677,81 +1678,65 @@ pub struct Arg { pub id: NodeId, } -/// Represents the kind of 'self' associated with a method. -/// String representation of `Ident` here is always "self", but hygiene contexts may differ. +/// Alternative representation for `Arg`s describing `self` parameter of methods. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum SelfKind { - /// No self - Static, /// `self`, `mut self` - Value(Ident), + Value(Mutability), /// `&'lt self`, `&'lt mut self` - Region(Option, Mutability, Ident), + Region(Option, Mutability), /// `self: TYPE`, `mut self: TYPE` - Explicit(P, Ident), + Explicit(P, Mutability), } pub type ExplicitSelf = Spanned; impl Arg { - #[unstable(feature = "rustc_private", issue = "27812")] - #[rustc_deprecated(since = "1.10.0", reason = "use `from_self` instead")] - pub fn new_self(span: Span, mutability: Mutability, self_ident: Ident) -> Arg { - let path = Spanned{span:span,node:self_ident}; - Arg { - // HACK(eddyb) fake type for the self argument. - ty: P(Ty { - id: DUMMY_NODE_ID, - node: TyKind::Infer, - span: DUMMY_SP, - }), - pat: P(Pat { - id: DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(mutability), path, None), - span: span - }), - id: DUMMY_NODE_ID - } - } - pub fn to_self(&self) -> Option { - if let PatKind::Ident(_, ident, _) = self.pat.node { + if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { if ident.node.name == keywords::SelfValue.name() { return match self.ty.node { - TyKind::Infer => Some(respan(self.pat.span, SelfKind::Value(ident.node))), + TyKind::Infer => Some(respan(self.pat.span, SelfKind::Value(mutbl))), TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::Infer => { - Some(respan(self.pat.span, SelfKind::Region(lt, mutbl, ident.node))) + Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) } _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi), - SelfKind::Explicit(self.ty.clone(), ident.node))), + SelfKind::Explicit(self.ty.clone(), mutbl))), } } } None } - pub fn from_self(eself: ExplicitSelf, ident_sp: Span, mutbl: Mutability) -> Arg { - let pat = |ident, span| P(Pat { - id: DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(mutbl), respan(ident_sp, ident), None), - span: span, - }); + pub fn is_self(&self) -> bool { + if let PatKind::Ident(_, ident, _) = self.pat.node { + ident.node.name == keywords::SelfValue.name() + } else { + false + } + } + + pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg { let infer_ty = P(Ty { id: DUMMY_NODE_ID, node: TyKind::Infer, span: DUMMY_SP, }); - let arg = |ident, ty, span| Arg { - pat: pat(ident, span), + let arg = |mutbl, ty, span| Arg { + pat: P(Pat { + id: DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), + span: span, + }), ty: ty, id: DUMMY_NODE_ID, }; match eself.node { - SelfKind::Static => panic!("bug: `Arg::from_self` is called \ - with `SelfKind::Static` argument"), - SelfKind::Explicit(ty, ident) => arg(ident, ty, mk_sp(eself.span.lo, ident_sp.hi)), - SelfKind::Value(ident) => arg(ident, infer_ty, eself.span), - SelfKind::Region(lt, mutbl, ident) => arg(ident, P(Ty { + SelfKind::Explicit(ty, mutbl) => { + arg(mutbl, ty, mk_sp(eself.span.lo, eself_ident.span.hi)) + } + SelfKind::Value(mutbl) => arg(mutbl, infer_ty, eself.span), + SelfKind::Region(lt, mutbl) => arg(Mutability::Immutable, P(Ty { id: DUMMY_NODE_ID, node: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl: mutbl }), span: DUMMY_SP, @@ -1768,6 +1753,15 @@ pub struct FnDecl { pub variadic: bool } +impl FnDecl { + pub fn get_self(&self) -> Option { + self.inputs.get(0).and_then(Arg::to_self) + } + pub fn has_self(&self) -> bool { + self.inputs.get(0).map(Arg::is_self).unwrap_or(false) + } +} + #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Unsafety { Unsafe, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 56374e935931..f217850e5fc6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -950,7 +950,7 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P, (ast::MethodSig { generics: fld.fold_generics(sig.generics), abi: sig.abi, - explicit_self: fld.fold_explicit_self(sig.explicit_self), + self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: rewritten_fn_decl diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index f25be190537d..d40eba8f3ffb 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -179,14 +179,6 @@ pub trait Folder : Sized { // fold::noop_fold_mac(_mac, self) } - fn fold_explicit_self(&mut self, es: ExplicitSelf) -> ExplicitSelf { - noop_fold_explicit_self(es, self) - } - - fn fold_explicit_self_kind(&mut self, es: SelfKind) -> SelfKind { - noop_fold_explicit_self_kind(es, self) - } - fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime { noop_fold_lifetime(l, self) } @@ -523,28 +515,6 @@ pub fn noop_fold_attribute(at: Attribute, fld: &mut T) -> Option(es: SelfKind, fld: &mut T) - -> SelfKind { - match es { - SelfKind::Static | SelfKind::Value(_) => es, - SelfKind::Region(lifetime, m, ident) => { - SelfKind::Region(fld.fold_opt_lifetime(lifetime), m, ident) - } - SelfKind::Explicit(typ, ident) => { - SelfKind::Explicit(fld.fold_ty(typ), ident) - } - } -} - -pub fn noop_fold_explicit_self(Spanned {span, node}: ExplicitSelf, fld: &mut T) - -> ExplicitSelf { - Spanned { - node: fld.fold_explicit_self_kind(node), - span: fld.new_span(span) - } -} - - pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac { Spanned { node: Mac_ { @@ -1096,7 +1066,7 @@ pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> Method MethodSig { generics: folder.fold_generics(sig.generics), abi: sig.abi, - explicit_self: folder.fold_explicit_self(sig.explicit_self), + self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: folder.fold_fn_decl(sig.decl) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b616b9db9c3b..7613eaf1b9af 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -17,7 +17,7 @@ use ast::Block; use ast::{BlockCheckMode, CaptureBy}; use ast::{Constness, Crate, CrateConfig}; use ast::{Decl, DeclKind, Defaultness}; -use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf}; +use ast::{EMPTY_CTXT, EnumDef}; use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; @@ -1310,7 +1310,7 @@ impl<'a> Parser<'a> { let ident = p.parse_ident()?; let mut generics = p.parse_generics()?; - let (explicit_self, d) = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ + let (d, self_shortcut) = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1324,7 +1324,7 @@ impl<'a> Parser<'a> { decl: d, generics: generics, abi: abi, - explicit_self: explicit_self, + self_shortcut: self_shortcut, }; let body = match p.token { @@ -4617,25 +4617,19 @@ impl<'a> Parser<'a> { })) } - /// Parse the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self(&mut self, - parse_arg_fn: F) - -> PResult<'a, (ExplicitSelf, P)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, - { + /// Returns the parsed optional self argument and whether a self shortcut was used. + fn parse_self_arg(&mut self) -> PResult<'a, (Option, bool)> { let expect_ident = |this: &mut Self| match this.token { - token::Ident(ident) => { this.bump(); ident } // Preserve hygienic context. + // Preserve hygienic context. + token::Ident(ident) => { this.bump(); codemap::respan(this.last_span, ident) } _ => unreachable!() }; - self.expect(&token::OpenDelim(token::Paren))?; - // Parse optional self parameter of a method. // Only a limited set of initial token sequences is considered self parameters, anything // else is parsed as a normal function parameter list, so some lookahead is required. let eself_lo = self.span.lo; - let mut eself_mutbl = Mutability::Immutable; - let (eself, eself_ident_sp) = match self.token { + let (eself, eself_ident) = match self.token { token::BinOp(token::And) => { // &self // &mut self @@ -4644,30 +4638,26 @@ impl<'a> Parser<'a> { // ¬_self if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); - (SelfKind::Region(None, Mutability::Immutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(None, Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); self.bump(); - (SelfKind::Region(None, Mutability::Mutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(None, Mutability::Mutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); let lt = self.parse_lifetime()?; - (SelfKind::Region(Some(lt), Mutability::Immutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && self.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); let lt = self.parse_lifetime()?; self.bump(); - (SelfKind::Region(Some(lt), Mutability::Mutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { - (SelfKind::Static, codemap::DUMMY_SP) + return Ok((None, false)); } } token::BinOp(token::Star) => { @@ -4679,15 +4669,15 @@ impl<'a> Parser<'a> { if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); self.span_err(self.span, "cannot pass `self` by raw pointer"); - (SelfKind::Value(expect_ident(self)), self.last_span) + (SelfKind::Value(Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_mutability()) && self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); self.bump(); self.span_err(self.span, "cannot pass `self` by raw pointer"); - (SelfKind::Value(expect_ident(self)), self.last_span) + (SelfKind::Value(Mutability::Immutable), expect_ident(self)) } else { - (SelfKind::Static, codemap::DUMMY_SP) + return Ok((None, false)); } } token::Ident(..) => { @@ -4695,64 +4685,72 @@ impl<'a> Parser<'a> { // self // self: TYPE let eself_ident = expect_ident(self); - let eself_ident_sp = self.last_span; if self.eat(&token::Colon) { - (SelfKind::Explicit(self.parse_ty_sum()?, eself_ident), eself_ident_sp) + let ty = self.parse_ty_sum()?; + (SelfKind::Explicit(ty, Mutability::Immutable), eself_ident) } else { - (SelfKind::Value(eself_ident), eself_ident_sp) + (SelfKind::Value(Mutability::Immutable), eself_ident) } } else if self.token.is_keyword(keywords::Mut) && self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { // mut self // mut self: TYPE - eself_mutbl = Mutability::Mutable; self.bump(); let eself_ident = expect_ident(self); - let eself_ident_sp = self.last_span; if self.eat(&token::Colon) { - (SelfKind::Explicit(self.parse_ty_sum()?, eself_ident), eself_ident_sp) + let ty = self.parse_ty_sum()?; + (SelfKind::Explicit(ty, Mutability::Mutable), eself_ident) } else { - (SelfKind::Value(eself_ident), eself_ident_sp) + (SelfKind::Value(Mutability::Mutable), eself_ident) } } else { - (SelfKind::Static, codemap::DUMMY_SP) + return Ok((None, false)); } } - _ => (SelfKind::Static, codemap::DUMMY_SP) + _ => return Ok((None, false)), }; - let mut eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself); + + let self_shortcut = if let SelfKind::Explicit(..) = eself { false } else { true }; + let eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself); + Ok((Some(Arg::from_self(eself, eself_ident)), self_shortcut)) + } + + /// Parse the parameter list and result type of a function that may have a `self` parameter. + fn parse_fn_decl_with_self(&mut self, + parse_arg_fn: F) + -> PResult<'a, (P, bool)> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, + { + self.expect(&token::OpenDelim(token::Paren))?; + + // Parse optional self argument + let (self_arg, self_shortcut) = self.parse_self_arg()?; // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); - let fn_inputs = match eself.node { - SelfKind::Static => { - eself.span = codemap::DUMMY_SP; - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn) - } - SelfKind::Value(..) | SelfKind::Region(..) | SelfKind::Explicit(..) => { - if self.check(&token::CloseDelim(token::Paren)) { - vec![Arg::from_self(eself.clone(), eself_ident_sp, eself_mutbl)] - } else if self.check(&token::Comma) { - self.bump(); - let mut fn_inputs = vec![Arg::from_self(eself.clone(), eself_ident_sp, - eself_mutbl)]; - fn_inputs.append(&mut self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), sep, parse_arg_fn) - ); - fn_inputs - } else { - return self.unexpected(); - } + let fn_inputs = if let Some(self_arg) = self_arg { + if self.check(&token::CloseDelim(token::Paren)) { + vec![self_arg] + } else if self.eat(&token::Comma) { + let mut fn_inputs = vec![self_arg]; + fn_inputs.append(&mut self.parse_seq_to_before_end( + &token::CloseDelim(token::Paren), sep, parse_arg_fn) + ); + fn_inputs + } else { + return self.unexpected(); } + } else { + self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn) }; // Parse closing paren and return type. self.expect(&token::CloseDelim(token::Paren))?; - Ok((eself, P(FnDecl { + Ok((P(FnDecl { inputs: fn_inputs, output: self.parse_ret_ty()?, variadic: false - }))) + }), self_shortcut)) } // parse the |arg, arg| header on a lambda @@ -4945,15 +4943,13 @@ impl<'a> Parser<'a> { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { - p.parse_arg() - })?; + let (decl, self_shortcut) = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig { generics: generics, abi: abi, - explicit_self: explicit_self, + self_shortcut: self_shortcut, unsafety: unsafety, constness: constness, decl: decl diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index fec84e912d49..96803ba6daef 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -12,7 +12,7 @@ pub use self::AnnNode::*; use abi::{self, Abi}; use ast::{self, TokenTree, BlockCheckMode, PatKind}; -use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; +use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use attr::ThinAttributesExt; use util::parser::AssocOp; @@ -382,13 +382,12 @@ pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, constness: ast::Constness, name: ast::Ident, - opt_explicit_self: Option<&ast::SelfKind>, generics: &ast::Generics) -> String { to_string(|s| { s.head("")?; s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name), - generics, opt_explicit_self, &ast::Visibility::Inherited)?; + generics, &ast::Visibility::Inherited)?; s.end()?; // Close the head box s.end() // Close the outer box }) @@ -416,10 +415,6 @@ pub fn lit_to_string(l: &ast::Lit) -> String { to_string(|s| s.print_literal(l)) } -pub fn explicit_self_to_string(explicit_self: &ast::SelfKind) -> String { - to_string(|s| s.print_explicit_self(explicit_self, ast::Mutability::Immutable).map(|_| {})) -} - pub fn variant_to_string(var: &ast::Variant) -> String { to_string(|s| s.print_variant(var)) } @@ -1005,8 +1000,7 @@ impl<'a> State<'a> { f.unsafety, &f.decl, None, - &generics, - None)?; + &generics)?; } ast::TyKind::Path(None, ref path) => { self.print_path(path, false, 0)?; @@ -1054,7 +1048,7 @@ impl<'a> State<'a> { self.print_fn(decl, ast::Unsafety::Normal, ast::Constness::NotConst, Abi::Rust, Some(item.ident), - generics, None, &item.vis)?; + generics, &item.vis)?; self.end()?; // end head-ibox word(&mut self.s, ";")?; self.end() // end the outer fn box @@ -1182,7 +1176,6 @@ impl<'a> State<'a> { abi, Some(item.ident), typarams, - None, &item.vis )?; word(&mut self.s, " ")?; @@ -1522,7 +1515,6 @@ impl<'a> State<'a> { m.abi, Some(ident), &m.generics, - None, vis) } @@ -2610,29 +2602,25 @@ impl<'a> State<'a> { self.end() // close enclosing cbox } - // Returns whether it printed anything - fn print_explicit_self(&mut self, - explicit_self: &ast::SelfKind, - mutbl: ast::Mutability) -> io::Result { - self.print_mutability(mutbl)?; - match *explicit_self { - ast::SelfKind::Static => { return Ok(false); } - ast::SelfKind::Value(_) => { - word(&mut self.s, "self")?; + fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) -> io::Result<()> { + match explicit_self.node { + SelfKind::Value(m) => { + self.print_mutability(m)?; + word(&mut self.s, "self") } - ast::SelfKind::Region(ref lt, m, _) => { + SelfKind::Region(ref lt, m) => { word(&mut self.s, "&")?; self.print_opt_lifetime(lt)?; self.print_mutability(m)?; - word(&mut self.s, "self")?; + word(&mut self.s, "self") } - ast::SelfKind::Explicit(ref typ, _) => { + SelfKind::Explicit(ref typ, m) => { + self.print_mutability(m)?; word(&mut self.s, "self")?; self.word_space(":")?; - self.print_type(&typ)?; + self.print_type(&typ) } } - return Ok(true); } pub fn print_fn(&mut self, @@ -2642,7 +2630,6 @@ impl<'a> State<'a> { abi: abi::Abi, name: Option, generics: &ast::Generics, - opt_explicit_self: Option<&ast::SelfKind>, vis: &ast::Visibility) -> io::Result<()> { self.print_fn_header_info(unsafety, constness, abi, vis)?; @@ -2651,21 +2638,14 @@ impl<'a> State<'a> { self.print_ident(name)?; } self.print_generics(generics)?; - self.print_fn_args_and_ret(decl, opt_explicit_self)?; + self.print_fn_args_and_ret(decl)?; self.print_where_clause(&generics.where_clause) } - pub fn print_fn_args(&mut self, decl: &ast::FnDecl, - _: Option<&ast::SelfKind>, - is_closure: bool) -> io::Result<()> { - self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, is_closure)) - } - - pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl, - opt_explicit_self: Option<&ast::SelfKind>) + pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl) -> io::Result<()> { self.popen()?; - self.print_fn_args(decl, opt_explicit_self, false)?; + self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?; if decl.variadic { word(&mut self.s, ", ...")?; } @@ -2679,7 +2659,7 @@ impl<'a> State<'a> { decl: &ast::FnDecl) -> io::Result<()> { word(&mut self.s, "|")?; - self.print_fn_args(decl, None, true)?; + self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?; word(&mut self.s, "|")?; if let ast::FunctionRetTy::Default(..) = decl.output { @@ -2929,17 +2909,14 @@ impl<'a> State<'a> { match input.ty.node { ast::TyKind::Infer if is_closure => self.print_pat(&input.pat)?, _ => { - let (mutbl, invalid) = match input.pat.node { - PatKind::Ident(ast::BindingMode::ByValue(mutbl), ident, _) | - PatKind::Ident(ast::BindingMode::ByRef(mutbl), ident, _) => { - (mutbl, ident.node.name == keywords::Invalid.name()) - } - _ => (ast::Mutability::Immutable, false) - }; - if let Some(eself) = input.to_self() { - self.print_explicit_self(&eself.node, mutbl)?; + self.print_explicit_self(&eself)?; } else { + let invalid = if let PatKind::Ident(_, ident, _) = input.pat.node { + ident.node.name == keywords::Invalid.name() + } else { + false + }; if !invalid { self.print_pat(&input.pat)?; word(&mut self.s, ":")?; @@ -2980,8 +2957,7 @@ impl<'a> State<'a> { unsafety: ast::Unsafety, decl: &ast::FnDecl, name: Option, - generics: &ast::Generics, - opt_explicit_self: Option<&ast::SelfKind>) + generics: &ast::Generics) -> io::Result<()> { self.ibox(INDENT_UNIT)?; if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { @@ -3002,7 +2978,6 @@ impl<'a> State<'a> { abi, name, &generics, - opt_explicit_self, &ast::Visibility::Inherited)?; self.end() } @@ -3126,8 +3101,7 @@ mod tests { let generics = ast::Generics::default(); assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, ast::Constness::NotConst, - abba_ident, - None, &generics), + abba_ident, &generics), "fn abba()"); } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index e692ec4452cd..919dd84b1179 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -129,10 +129,6 @@ impl<'v> Visitor<'v> for NodeCounter { self.count += 1; walk_lifetime_def(self, lifetime) } - fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { - self.count += 1; - walk_explicit_self(self, es) - } fn visit_mac(&mut self, _mac: &'v Mac) { self.count += 1; walk_mac(self, _mac) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 40b2e0bc47e2..df61aa4a5375 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -99,9 +99,6 @@ pub trait Visitor<'v> : Sized { fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) } - fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { - walk_explicit_self(self, es) - } fn visit_mac(&mut self, _mac: &'v Mac) { panic!("visit_mac disabled by default"); // NB: see note about macros above. @@ -203,24 +200,6 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); } -pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, - explicit_self: &'v ExplicitSelf) { - match explicit_self.node { - SelfKind::Static => {}, - SelfKind::Value(ident) => { - visitor.visit_ident(explicit_self.span, ident) - } - SelfKind::Region(ref opt_lifetime, _, ident) => { - visitor.visit_ident(explicit_self.span, ident); - walk_list!(visitor, visit_lifetime, opt_lifetime); - } - SelfKind::Explicit(ref typ, ident) => { - visitor.visit_ident(explicit_self.span, ident); - visitor.visit_ty(typ) - } - } -} - pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v PolyTraitRef, _modifier: &'v TraitBoundModifier) @@ -553,7 +532,6 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, } FnKind::Method(_, ref sig, _) => { visitor.visit_generics(&sig.generics); - visitor.visit_explicit_self(&sig.explicit_self); } FnKind::Closure => {} } @@ -578,7 +556,6 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_list!(visitor, visit_expr, default); } TraitItemKind::Method(ref sig, None) => { - visitor.visit_explicit_self(&sig.explicit_self); visitor.visit_generics(&sig.generics); walk_fn_decl(visitor, &sig.decl); } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 20fb4bf32ccb..6ecbdb765fac 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -197,7 +197,7 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::ext::base::{ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; -use syntax::codemap::{self, DUMMY_SP}; +use syntax::codemap::{self, respan, DUMMY_SP}; use syntax::codemap::Span; use syntax::errors::Handler; use syntax::util::move_map::MoveMap; @@ -806,25 +806,21 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef, type_ident: Ident, generics: &Generics) - -> (ast::ExplicitSelf, Vec>, Vec>, Vec<(Ident, P)>) { + -> (Option, Vec>, Vec>, Vec<(Ident, P)>) { let mut self_args = Vec::new(); let mut nonself_args = Vec::new(); let mut arg_tys = Vec::new(); let mut nonstatic = false; - let ast_explicit_self = match self.explicit_self { - Some(ref self_ptr) => { - let (self_expr, explicit_self) = - ty::get_explicit_self(cx, trait_.span, self_ptr); + let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| { + let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr); - self_args.push(self_expr); - nonstatic = true; + self_args.push(self_expr); + nonstatic = true; - explicit_self - } - None => codemap::respan(trait_.span, ast::SelfKind::Static), - }; + explicit_self + }); for (i, ty) in self.args.iter().enumerate() { let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); @@ -857,24 +853,22 @@ impl<'a> MethodDef<'a> { type_ident: Ident, generics: &Generics, abi: Abi, - explicit_self: ast::ExplicitSelf, + explicit_self: Option, arg_types: Vec<(Ident, P)> , body: P) -> ast::ImplItem { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - let self_arg = match explicit_self.node { - ast::SelfKind::Static => None, - // creating fresh self id - _ => Some(ast::Arg::from_self(explicit_self.clone(), trait_.span, - ast::Mutability::Immutable)), - }; + // derive doesn't generate `self: TYPE` forms + let self_shortcut = explicit_self.is_some(); let args = { - let args = arg_types.into_iter().map(|(name, ty)| { - cx.arg(trait_.span, name, ty) - }); - self_arg.into_iter().chain(args).collect() + let self_args = explicit_self.map(|explicit_self| { + ast::Arg::from_self(explicit_self, respan(trait_.span, keywords::SelfValue.ident())) + }); + let nonself_args = arg_types.into_iter() + .map(|(name, ty)| cx.arg(trait_.span, name, ty)); + self_args.into_iter().chain(nonself_args).collect() }; let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); @@ -900,7 +894,7 @@ impl<'a> MethodDef<'a> { node: ast::ImplItemKind::Method(ast::MethodSig { generics: fn_generics, abi: abi, - explicit_self: explicit_self, + self_shortcut: self_shortcut, unsafety: unsafety, constness: ast::Constness::NotConst, decl: fn_decl diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index e31d45d91a59..b581f5267eaa 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -15,11 +15,10 @@ pub use self::PtrTy::*; pub use self::Ty::*; use syntax::ast; -use syntax::ast::{Expr,Generics,Ident}; +use syntax::ast::{Expr, Generics, Ident, SelfKind}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::codemap::{Span,respan}; -use syntax::parse::token::keywords; use syntax::ptr::P; /// The types of pointers @@ -258,12 +257,11 @@ impl<'a> LifetimeBounds<'a> { pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) -> (P, ast::ExplicitSelf) { - // this constructs a fresh `self` path, which will match the fresh `self` binding - // created below. + // this constructs a fresh `self` path let self_path = cx.expr_self(span); match *self_ptr { None => { - (self_path, respan(span, ast::SelfKind::Value(keywords::SelfValue.ident()))) + (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))) } Some(ref ptr) => { let self_ty = respan( @@ -271,7 +269,7 @@ pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) match *ptr { Borrowed(ref lt, mutbl) => { let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); - ast::SelfKind::Region(lt, mutbl, keywords::SelfValue.ident()) + SelfKind::Region(lt, mutbl) } Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition") }); From 470e403a265e4162a8f9b5cb3e4eb51e15dbd27c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 145/179] Add a new AST-only type variant `ImplicitSelf` --- src/librustc/hir/lowering.rs | 23 +++++++++--------- src/libsyntax/ast.rs | 10 ++++---- src/libsyntax/ext/expand.rs | 1 - src/libsyntax/fold.rs | 3 +-- src/libsyntax/parse/parser.rs | 29 ++++++++++------------- src/libsyntax/print/pprust.rs | 3 +++ src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 3 --- 8 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ac6c9ad64f3a..6b0021f70f08 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -273,7 +273,7 @@ impl<'a> LoweringContext<'a> { P(hir::Ty { id: t.id, node: match t.node { - Infer => hir::TyInfer, + Infer | ImplicitSelf => hir::TyInfer, Vec(ref ty) => hir::TyVec(self.lower_ty(ty)), Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), Rptr(ref region, ref mt) => { @@ -791,23 +791,24 @@ impl<'a> LoweringContext<'a> { } fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig { + let hir_sig = hir::MethodSig { + generics: self.lower_generics(&sig.generics), + abi: sig.abi, + unsafety: self.lower_unsafety(sig.unsafety), + constness: self.lower_constness(sig.constness), + decl: self.lower_fn_decl(&sig.decl), + }; // Check for `self: _` and `self: &_` - if !sig.self_shortcut { - match sig.decl.get_self().map(|eself| eself.node) { - Some(SelfKind::Value(..)) | Some(SelfKind::Region(..)) => { + if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) { + match hir_sig.decl.get_self().map(|eself| eself.node) { + Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => { self.id_assigner.diagnostic().span_err(sig.decl.inputs[0].ty.span, "the type placeholder `_` is not allowed within types on item signatures"); } _ => {} } } - hir::MethodSig { - generics: self.lower_generics(&sig.generics), - abi: sig.abi, - unsafety: self.lower_unsafety(sig.unsafety), - constness: self.lower_constness(sig.constness), - decl: self.lower_fn_decl(&sig.decl), - } + hir_sig } fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9c87fda62833..cbd024c5415f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1387,8 +1387,6 @@ pub struct MethodSig { pub abi: Abi, pub decl: P, pub generics: Generics, - /// A short form of self argument was used (`self`, `&self` etc, but not `self: TYPE`). - pub self_shortcut: bool, } /// Represents an item declaration within a trait declaration, @@ -1639,6 +1637,8 @@ pub enum TyKind { /// TyKind::Infer means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. Infer, + /// Inferred type of a `self` or `&self` argument in a method. + ImplicitSelf, // A macro in the type position. Mac(Mac), } @@ -1696,8 +1696,8 @@ impl Arg { if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { if ident.node.name == keywords::SelfValue.name() { return match self.ty.node { - TyKind::Infer => Some(respan(self.pat.span, SelfKind::Value(mutbl))), - TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::Infer => { + TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), + TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => { Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) } _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi), @@ -1719,7 +1719,7 @@ impl Arg { pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg { let infer_ty = P(Ty { id: DUMMY_NODE_ID, - node: TyKind::Infer, + node: TyKind::ImplicitSelf, span: DUMMY_SP, }); let arg = |mutbl, ty, span| Arg { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f217850e5fc6..ecca370fb8a3 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -950,7 +950,6 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P, (ast::MethodSig { generics: fld.fold_generics(sig.generics), abi: sig.abi, - self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: rewritten_fn_decl diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d40eba8f3ffb..063e485b153b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -375,7 +375,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { t.map(|Ty {id, node, span}| Ty { id: fld.new_id(id), node: match node { - TyKind::Infer => node, + TyKind::Infer | TyKind::ImplicitSelf => node, TyKind::Vec(ty) => TyKind::Vec(fld.fold_ty(ty)), TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)), TyKind::Rptr(region, mt) => { @@ -1066,7 +1066,6 @@ pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> Method MethodSig { generics: folder.fold_generics(sig.generics), abi: sig.abi, - self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: folder.fold_fn_decl(sig.decl) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7613eaf1b9af..f6f0d502a095 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1310,7 +1310,7 @@ impl<'a> Parser<'a> { let ident = p.parse_ident()?; let mut generics = p.parse_generics()?; - let (d, self_shortcut) = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ + let d = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1324,7 +1324,6 @@ impl<'a> Parser<'a> { decl: d, generics: generics, abi: abi, - self_shortcut: self_shortcut, }; let body = match p.token { @@ -4618,7 +4617,7 @@ impl<'a> Parser<'a> { } /// Returns the parsed optional self argument and whether a self shortcut was used. - fn parse_self_arg(&mut self) -> PResult<'a, (Option, bool)> { + fn parse_self_arg(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. token::Ident(ident) => { this.bump(); codemap::respan(this.last_span, ident) } @@ -4657,7 +4656,7 @@ impl<'a> Parser<'a> { self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { - return Ok((None, false)); + return Ok(None); } } token::BinOp(token::Star) => { @@ -4677,7 +4676,7 @@ impl<'a> Parser<'a> { self.span_err(self.span, "cannot pass `self` by raw pointer"); (SelfKind::Value(Mutability::Immutable), expect_ident(self)) } else { - return Ok((None, false)); + return Ok(None); } } token::Ident(..) => { @@ -4704,27 +4703,24 @@ impl<'a> Parser<'a> { (SelfKind::Value(Mutability::Mutable), eself_ident) } } else { - return Ok((None, false)); + return Ok(None); } } - _ => return Ok((None, false)), + _ => return Ok(None), }; - let self_shortcut = if let SelfKind::Explicit(..) = eself { false } else { true }; let eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself); - Ok((Some(Arg::from_self(eself, eself_ident)), self_shortcut)) + Ok(Some(Arg::from_self(eself, eself_ident))) } /// Parse the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self(&mut self, - parse_arg_fn: F) - -> PResult<'a, (P, bool)> + fn parse_fn_decl_with_self(&mut self, parse_arg_fn: F) -> PResult<'a, P> where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, { self.expect(&token::OpenDelim(token::Paren))?; // Parse optional self argument - let (self_arg, self_shortcut) = self.parse_self_arg()?; + let self_arg = self.parse_self_arg()?; // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); @@ -4746,11 +4742,11 @@ impl<'a> Parser<'a> { // Parse closing paren and return type. self.expect(&token::CloseDelim(token::Paren))?; - Ok((P(FnDecl { + Ok(P(FnDecl { inputs: fn_inputs, output: self.parse_ret_ty()?, variadic: false - }), self_shortcut)) + })) } // parse the |arg, arg| header on a lambda @@ -4943,13 +4939,12 @@ impl<'a> Parser<'a> { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let (decl, self_shortcut) = self.parse_fn_decl_with_self(|p| p.parse_arg())?; + let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig { generics: generics, abi: abi, - self_shortcut: self_shortcut, unsafety: unsafety, constness: constness, decl: decl diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 96803ba6daef..9e899395b6cd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1030,6 +1030,9 @@ impl<'a> State<'a> { ast::TyKind::Infer => { word(&mut self.s, "_")?; } + ast::TyKind::ImplicitSelf => { + unreachable!(); + } ast::TyKind::Mac(ref m) => { self.print_mac(m, token::Paren)?; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index df61aa4a5375..a00a5adfb826 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -352,7 +352,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyKind::Typeof(ref expression) => { visitor.visit_expr(expression) } - TyKind::Infer => {} + TyKind::Infer | TyKind::ImplicitSelf => {} TyKind::Mac(ref mac) => { visitor.visit_mac(mac) } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 6ecbdb765fac..9095230df630 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -860,8 +860,6 @@ impl<'a> MethodDef<'a> { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - // derive doesn't generate `self: TYPE` forms - let self_shortcut = explicit_self.is_some(); let args = { let self_args = explicit_self.map(|explicit_self| { ast::Arg::from_self(explicit_self, respan(trait_.span, keywords::SelfValue.ident())) @@ -894,7 +892,6 @@ impl<'a> MethodDef<'a> { node: ast::ImplItemKind::Method(ast::MethodSig { generics: fn_generics, abi: abi, - self_shortcut: self_shortcut, unsafety: unsafety, constness: ast::Constness::NotConst, decl: fn_decl From cf121b794b6fe38da5baf4a3bd95ed76e65811b9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 146/179] Fix rebase --- src/librustc_resolve/lib.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 597a29d1aac6..4fc3abb99332 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -67,7 +67,7 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Pat, PatKind, Path}; -use syntax::ast::{PathSegment, PathParameters, SelfKind, TraitItemKind, TraitRef, Ty, TyKind}; +use syntax::ast::{PathSegment, PathParameters, TraitItemKind, TraitRef, Ty, TyKind}; use std::collections::{HashMap, HashSet}; use std::cell::{Cell, RefCell}; @@ -607,7 +607,7 @@ impl<'a, 'v> Visitor<'v> for Resolver<'a> { } FnKind::Method(_, sig, _) => { self.visit_generics(&sig.generics); - MethodRibKind(sig.explicit_self.node == SelfKind::Static) + MethodRibKind(!sig.decl.has_self()) } FnKind::Closure => ClosureRibKind(node_id), }; @@ -1676,9 +1676,7 @@ impl<'a> Resolver<'a> { let type_parameters = HasTypeParameters(&sig.generics, FnSpace, - MethodRibKind( - sig.explicit_self.node == - SelfKind::Static)); + MethodRibKind(!sig.decl.has_self())); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_trait_item(this, trait_item) }); @@ -2007,9 +2005,7 @@ impl<'a> Resolver<'a> { let type_parameters = HasTypeParameters(&sig.generics, FnSpace, - MethodRibKind( - sig.explicit_self.node == - SelfKind::Static)); + MethodRibKind(!sig.decl.has_self())); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_impl_item(this, impl_item); }); From 79c1fdcd0616f4264795aaa263f4745a6a540742 Mon Sep 17 00:00:00 2001 From: Carlo Teubner Date: Wed, 18 May 2016 22:42:15 +0100 Subject: [PATCH 147/179] parser.rs: fix typos in comments --- src/libsyntax/parse/parser.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f6f0d502a095..e0e0dc98d09c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2807,14 +2807,14 @@ impl<'a> Parser<'a> { let span = Span { hi: close_span.hi, ..pre_span }; match self.token { - // Correct delmiter. + // Correct delimiter. token::CloseDelim(d) if d == delim => { self.open_braces.pop().unwrap(); // Parse the close delimiter. self.bump(); } - // Incorect delimiter. + // Incorrect delimiter. token::CloseDelim(other) => { let token_str = self.this_token_to_string(); let mut err = self.diagnostic().struct_span_err(self.span, @@ -2829,9 +2829,9 @@ impl<'a> Parser<'a> { self.open_braces.pop().unwrap(); - // If the incorrect delimter matches an earlier opening + // If the incorrect delimiter matches an earlier opening // delimiter, then don't consume it (it can be used to - // close the earlier one)Otherwise, consume it. + // close the earlier one). Otherwise, consume it. // E.g., we try to recover from: // fn foo() { // bar(baz( @@ -2859,7 +2859,7 @@ impl<'a> Parser<'a> { // invariants: the current token is not a left-delimiter, // not an EOF, and not the desired right-delimiter (if // it were, parse_seq_to_before_end would have prevented - // reaching this point. + // reaching this point). maybe_whole!(deref self, NtTT); match self.token { token::CloseDelim(_) => { From 5dcc8c215517f6c7c17ff9c5c642ec74ac03f34a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 May 2016 02:45:13 +0300 Subject: [PATCH 148/179] Fix handling of C arguments Fixes #33868 --- src/librustc_trans/base.rs | 37 ++++++++++++++++++++++------------- src/librustc_trans/mir/mod.rs | 17 ++++++++++------ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 03e12c1c8a7b..5a9b4e109a5b 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1663,21 +1663,30 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { arg_ty, datum::Lvalue::new("FunctionContext::bind_args")) } else { - unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", - uninit_reason, - arg_scope_id, |bcx, dst| { - debug!("FunctionContext::bind_args: {:?}: {:?}", hir_arg, arg_ty); + let lltmp = if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { + let lltemp = alloc_ty(bcx, arg_ty, ""); let b = &bcx.build(); - if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { - let meta = &self.fn_ty.args[idx]; - idx += 1; - arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst)); - meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst)); - } else { - arg.store_fn_arg(b, &mut llarg_idx, dst); - } - bcx - })) + // we pass fat pointers as two words, but we want to + // represent them internally as a pointer to two words, + // so make an alloca to store them in. + let meta = &self.fn_ty.args[idx]; + idx += 1; + arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, lltemp)); + meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, lltemp)); + lltemp + } else { + // otherwise, arg is passed by value, so store it into a temporary. + let llarg_ty = arg.cast.unwrap_or(arg.memory_ty(bcx.ccx())); + let lltemp = alloca(bcx, llarg_ty, ""); + let b = &bcx.build(); + arg.store_fn_arg(b, &mut llarg_idx, lltemp); + // And coerce the temporary into the type we expect. + b.pointercast(lltemp, arg.memory_ty(bcx.ccx()).ptr_to()) + }; + + // FIXME: hacky lol? + datum::Datum::new(lltmp, arg_ty, + datum::Lvalue::new("datum::lvalue_scratch_datum")) } } else { // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index b98e04e51c00..ffc14b4468b5 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -327,10 +327,10 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, llarg_idx += 1; llarg } else { - let lltemp = bcx.with_block(|bcx| { - base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)) - }); if common::type_is_fat_ptr(tcx, arg_ty) { + let lltemp = bcx.with_block(|bcx| { + base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)) + }); // we pass fat pointers as two words, but we want to // represent them internally as a pointer to two words, // so make an alloca to store them in. @@ -338,12 +338,17 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, idx += 1; arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, lltemp)); meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, lltemp)); + lltemp } else { - // otherwise, arg is passed by value, so make a - // temporary and store it there + // otherwise, arg is passed by value, so store it into a temporary. + let llarg_ty = arg.cast.unwrap_or(arg.memory_ty(bcx.ccx())); + let lltemp = bcx.with_block(|bcx| { + base::alloca(bcx, llarg_ty, &format!("arg{}", arg_index)) + }); arg.store_fn_arg(bcx, &mut llarg_idx, lltemp); + // And coerce the temporary into the type we expect. + bcx.pointercast(lltemp, arg.memory_ty(bcx.ccx()).ptr_to()) } - lltemp }; bcx.with_block(|bcx| arg_scope.map(|scope| { // Is this a regular argument? From 6fe158789c443e8c43f0f3f85988654d32d054f4 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 May 2016 02:48:25 +0300 Subject: [PATCH 149/179] Add a regression test --- .../run-pass/foreign-truncated-arguments.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/test/run-pass/foreign-truncated-arguments.rs diff --git a/src/test/run-pass/foreign-truncated-arguments.rs b/src/test/run-pass/foreign-truncated-arguments.rs new file mode 100644 index 000000000000..a983a4a95988 --- /dev/null +++ b/src/test/run-pass/foreign-truncated-arguments.rs @@ -0,0 +1,29 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O +// Regression test for https://github.com/rust-lang/rust/issues/33868 + +#[repr(C)] +pub struct S { + a: u32, + b: f32, + c: u32 +} + +#[no_mangle] +#[inline(never)] +pub extern "C" fn test(s: S) -> u32 { + s.c +} + +fn main() { + assert_eq!(test(S{a: 0, b: 0.0, c: 42}), 42); +} From d7ea38d106e1bc4f338f2a3e2355264c66e12ba8 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 May 2016 03:13:32 +0300 Subject: [PATCH 150/179] Fix the fix/hack interaction with debuginfo --- src/librustc_trans/base.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 5a9b4e109a5b..f190015d0249 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1721,16 +1721,19 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { }; let pat = &hir_arg.pat; - bcx = if let Some(name) = simple_name(pat) { - // Generate nicer LLVM for the common case of fn a pattern - // like `x: T` - set_value_name(arg_datum.val, &bcx.name(name)); - self.lllocals.borrow_mut().insert(pat.id, arg_datum); - bcx - } else { - // General path. Copy out the values that are used in the - // pattern. - _match::bind_irrefutable_pat(bcx, pat, arg_datum.match_input(), arg_scope_id) + bcx = match simple_name(pat) { + // The check for alloca is necessary because above for the immediate argument case + // we had to cast. At this point arg_datum is not an alloca anymore and thus + // breaks debuginfo if we allow this optimisation. + Some(name) + if unsafe { llvm::LLVMIsAAllocaInst(arg_datum.val) != ::std::ptr::null_mut() } => { + // Generate nicer LLVM for the common case of fn a pattern + // like `x: T` + set_value_name(arg_datum.val, &bcx.name(name)); + self.lllocals.borrow_mut().insert(pat.id, arg_datum); + bcx + }, + _ => _match::bind_irrefutable_pat(bcx, pat, arg_datum.match_input(), arg_scope_id) }; debuginfo::create_argument_metadata(bcx, hir_arg); } From 0a4439b957727407f5ea55f5602e9aaceb1fb9b4 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 May 2016 03:38:17 +0300 Subject: [PATCH 151/179] Fix nit/Refine the datum construction --- src/librustc_trans/base.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f190015d0249..ddfa08516e59 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1683,10 +1683,8 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { // And coerce the temporary into the type we expect. b.pointercast(lltemp, arg.memory_ty(bcx.ccx()).ptr_to()) }; - - // FIXME: hacky lol? datum::Datum::new(lltmp, arg_ty, - datum::Lvalue::new("datum::lvalue_scratch_datum")) + datum::Lvalue::new("bind_args")) } } else { // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. From f0512ea837b7d29347df95381cc3b739cf44777a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 25 May 2016 20:05:47 +0000 Subject: [PATCH 152/179] Fix ICE on failure to parse token tree --- src/libsyntax/parse/parser.rs | 7 +++++-- src/test/parse-fail/issue-33569.rs | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/test/parse-fail/issue-33569.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e0e0dc98d09c..e25a4eece921 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2702,7 +2702,10 @@ impl<'a> Parser<'a> { return Ok(TokenTree::Token(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar))); } else { sp = mk_sp(sp.lo, self.span.hi); - self.parse_ident()? + self.parse_ident().unwrap_or_else(|mut e| { + e.emit(); + keywords::Invalid.ident() + }) } } token::SubstNt(name) => { @@ -2845,7 +2848,7 @@ impl<'a> Parser<'a> { // and an error emitted then. Thus we don't pop from // self.open_braces here. }, - _ => unreachable!(), + _ => {} } Ok(TokenTree::Delimited(span, Rc::new(Delimited { diff --git a/src/test/parse-fail/issue-33569.rs b/src/test/parse-fail/issue-33569.rs new file mode 100644 index 000000000000..130278d778ab --- /dev/null +++ b/src/test/parse-fail/issue-33569.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z no-analysis + +macro_rules! foo { + { $+ } => { //~ ERROR expected identifier, found `+` + $(x)(y) //~ ERROR expected `*` or `+` + //~^ ERROR no rules expected the token `y` + } +} From f7f61353afd7c59de43824c847dc461f0807f048 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 30 Dec 2015 10:08:28 +0100 Subject: [PATCH 153/179] `EscapeUnicode` and `EscapeDefault` are `ExactSizeIterator`s In #28662, `size_hint` was made exact for `EscapeUnicode` and `EscapeDefault`, but neither was marked as `ExactSizeIterator`. --- src/libcore/char.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 6a2331dddcf0..25d90cc6f3a4 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -483,6 +483,9 @@ impl Iterator for EscapeUnicode { } } +#[stable(feature = "exact_size_escape", since = "1.11.0")] +impl ExactSizeIterator for EscapeUnicode { } + /// An iterator that yields the literal escape code of a `char`. /// /// This `struct` is created by the [`escape_default()`] method on [`char`]. See @@ -578,6 +581,9 @@ impl Iterator for EscapeDefault { } } +#[stable(feature = "exact_size_escape", since = "1.11.0")] +impl ExactSizeIterator for EscapeDefault { } + /// An iterator over `u8` entries represending the UTF-8 encoding of a `char` /// value. /// From f5485731f067bc748df22a1ee73f2fd89773a990 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 30 Dec 2015 16:42:52 +0100 Subject: [PATCH 154/179] Implement `count` for `EscapeDefault` and `EscapeUnicode` Trivial implementation, as both are `ExactSizeIterator`s. Part of #24214. --- src/libcore/char.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 25d90cc6f3a4..f803b36cede9 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -470,6 +470,11 @@ impl Iterator for EscapeUnicode { (n, Some(n)) } + #[inline] + fn count(self) -> usize { + self.len() + } + fn last(self) -> Option { match self.state { EscapeUnicodeState::Done => None, @@ -535,13 +540,9 @@ impl Iterator for EscapeDefault { } } + #[inline] fn count(self) -> usize { - match self.state { - EscapeDefaultState::Char(_) => 1, - EscapeDefaultState::Unicode(iter) => iter.count(), - EscapeDefaultState::Done => 0, - EscapeDefaultState::Backslash(_) => 2, - } + self.len() } fn nth(&mut self, n: usize) -> Option { From 4ad727276127c4b072acbcdde2328e5c21bec6e4 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Mon, 18 Jan 2016 17:36:12 +0100 Subject: [PATCH 155/179] Move length computation to `ExactSizeIterator` impls and reuse it in `size_hint`. --- src/libcore/char.rs | 60 +++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index f803b36cede9..38337c7493ee 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -413,12 +413,12 @@ pub struct EscapeUnicode { #[derive(Clone, Debug)] enum EscapeUnicodeState { - Backslash, - Type, - LeftBrace, - Value, - RightBrace, Done, + RightBrace, + Value, + LeftBrace, + Type, + Backslash, } #[stable(feature = "rust1", since = "1.0.0")] @@ -457,16 +457,9 @@ impl Iterator for EscapeUnicode { } } + #[inline] fn size_hint(&self) -> (usize, Option) { - let n = match self.state { - EscapeUnicodeState::Backslash => 5, - EscapeUnicodeState::Type => 4, - EscapeUnicodeState::LeftBrace => 3, - EscapeUnicodeState::Value => 2, - EscapeUnicodeState::RightBrace => 1, - EscapeUnicodeState::Done => 0, - }; - let n = n + self.hex_digit_idx; + let n = self.len(); (n, Some(n)) } @@ -489,7 +482,20 @@ impl Iterator for EscapeUnicode { } #[stable(feature = "exact_size_escape", since = "1.11.0")] -impl ExactSizeIterator for EscapeUnicode { } +impl ExactSizeIterator for EscapeUnicode { + #[inline] + fn len(&self) -> usize { + // The match is a single memory access with no branching + self.hex_digit_idx + match self.state { + EscapeUnicodeState::Done => 0, + EscapeUnicodeState::RightBrace => 1, + EscapeUnicodeState::Value => 2, + EscapeUnicodeState::LeftBrace => 3, + EscapeUnicodeState::Type => 4, + EscapeUnicodeState::Backslash => 5, + } + } +} /// An iterator that yields the literal escape code of a `char`. /// @@ -506,9 +512,9 @@ pub struct EscapeDefault { #[derive(Clone, Debug)] enum EscapeDefaultState { - Backslash(char), - Char(char), Done, + Char(char), + Backslash(char), Unicode(EscapeUnicode), } @@ -531,13 +537,10 @@ impl Iterator for EscapeDefault { } } + #[inline] fn size_hint(&self) -> (usize, Option) { - match self.state { - EscapeDefaultState::Char(_) => (1, Some(1)), - EscapeDefaultState::Backslash(_) => (2, Some(2)), - EscapeDefaultState::Unicode(ref iter) => iter.size_hint(), - EscapeDefaultState::Done => (0, Some(0)), - } + let n = self.len(); + (n, Some(n)) } #[inline] @@ -583,7 +586,16 @@ impl Iterator for EscapeDefault { } #[stable(feature = "exact_size_escape", since = "1.11.0")] -impl ExactSizeIterator for EscapeDefault { } +impl ExactSizeIterator for EscapeDefault { + fn len(&self) -> usize { + match self.state { + EscapeDefaultState::Done => 0, + EscapeDefaultState::Char(_) => 1, + EscapeDefaultState::Backslash(_) => 2, + EscapeDefaultState::Unicode(ref iter) => iter.len(), + } + } +} /// An iterator over `u8` entries represending the UTF-8 encoding of a `char` /// value. From 061397e8cdc239daf40d02cd350cfbe7c525e03a Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Thu, 26 May 2016 10:04:05 +0200 Subject: [PATCH 156/179] Explain the order of the enumeration items Simply a micro-optimization to reduce code size and to open up inlining opportunities. --- src/libcore/char.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 38337c7493ee..d80b456181ae 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -411,6 +411,9 @@ pub struct EscapeUnicode { hex_digit_idx: usize, } +// The enum values are ordered so that their representation is the +// same as the remaining length (besides the hexadecimal digits). This +// likely makes `len()` a single load from memory) and inline-worth. #[derive(Clone, Debug)] enum EscapeUnicodeState { Done, From cd1ba6bab4163064bfac59c5bf94b8fb60808336 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 26 May 2016 10:08:45 +0200 Subject: [PATCH 157/179] Add `make tips` as useful make target By accident, I found the `make tips` target, which helped me to gain more insight on how to work with the system more quickly. --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d61feef81a8..495d7e46baa6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -122,6 +122,8 @@ To see a full list of options, run `./configure --help`. Some common make targets are: +- `make tips` - show useful targets, variables and other tips for working with + the build system. - `make rustc-stage1` - build up to (and including) the first stage. For most cases we don't need to build the stage2 compiler, so we can save time by not building it. The stage1 compiler is a fully functioning compiler and From 7a6fc457e3a6d4f0502f4cd983ed48a2a1755594 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 158/179] Implement `..` in tuple (struct) patterns --- src/doc/reference.md | 2 + src/librustc/cfg/construct.rs | 5 +- src/librustc/hir/fold.rs | 8 +- src/librustc/hir/intravisit.rs | 8 +- src/librustc/hir/lowering.rs | 12 +- src/librustc/hir/mod.rs | 16 +- src/librustc/hir/pat_util.rs | 22 ++ src/librustc/hir/print.rs | 41 +++- src/librustc/lib.rs | 2 + src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 33 ++- src/librustc/middle/region.rs | 4 +- src/librustc/middle/stability.rs | 9 +- src/librustc_const_eval/check_match.rs | 33 ++- src/librustc_const_eval/eval.rs | 9 +- src/librustc_const_eval/lib.rs | 1 + src/librustc_mir/hair/cx/pattern.rs | 45 ++-- src/librustc_privacy/lib.rs | 13 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_trans/_match.rs | 79 +++---- .../debuginfo/create_scope_map.rs | 10 +- src/librustc_typeck/check/_match.rs | 92 ++++---- src/librustc_typeck/diagnostics.rs | 25 --- src/librustc_typeck/lib.rs | 3 +- src/librustdoc/clean/mod.rs | 4 +- src/libsyntax/ast.rs | 16 +- src/libsyntax/ext/build.rs | 4 +- src/libsyntax/feature_gate.rs | 24 ++- src/libsyntax/fold.rs | 8 +- src/libsyntax/parse/parser.rs | 65 ++---- src/libsyntax/print/pprust.rs | 44 ++-- src/libsyntax/visit.rs | 8 +- src/test/compile-fail/issue-32004.rs | 4 +- .../match-pattern-field-mismatch-2.rs | 2 +- src/test/compile-fail/pat-tuple-bad-type.rs | 27 +++ .../compile-fail/pat-tuple-feature-gate.rs | 17 ++ src/test/compile-fail/pat-tuple-overfield.rs | 28 +++ .../compile-fail/pattern-error-continue.rs | 2 +- src/test/parse-fail/pat-lt-bracket-6.rs | 3 +- src/test/parse-fail/pat-lt-bracket-7.rs | 3 +- .../E0024.rs => parse-fail/pat-tuple-1.rs} | 11 +- src/test/parse-fail/pat-tuple-2.rs | 17 ++ src/test/parse-fail/pat-tuple-3.rs | 17 ++ src/test/parse-fail/pat-tuple-4.rs | 17 ++ src/test/parse-fail/pat-tuple-5.rs | 17 ++ src/test/parse-fail/pat-tuple-6.rs | 17 ++ src/test/run-pass/pat-tuple.rs | 202 ++++++++++++++++++ 48 files changed, 736 insertions(+), 299 deletions(-) create mode 100644 src/test/compile-fail/pat-tuple-bad-type.rs create mode 100644 src/test/compile-fail/pat-tuple-feature-gate.rs create mode 100644 src/test/compile-fail/pat-tuple-overfield.rs rename src/test/{compile-fail/E0024.rs => parse-fail/pat-tuple-1.rs} (74%) create mode 100644 src/test/parse-fail/pat-tuple-2.rs create mode 100644 src/test/parse-fail/pat-tuple-3.rs create mode 100644 src/test/parse-fail/pat-tuple-4.rs create mode 100644 src/test/parse-fail/pat-tuple-5.rs create mode 100644 src/test/parse-fail/pat-tuple-6.rs create mode 100644 src/test/run-pass/pat-tuple.rs diff --git a/src/doc/reference.md b/src/doc/reference.md index ebb111a2e2e7..810138e5a298 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2433,6 +2433,8 @@ The currently implemented features of the reference compiler are: * - `abi_vectorcall` - Allows the usage of the vectorcall calling convention (e.g. `extern "vectorcall" func fn_();`) +* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled the new feature (because the directive is no longer necessary). However, if a diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 76699f13959e..af47617ea92f 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -100,7 +100,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex { match pat.node { PatKind::Ident(_, _, None) | - PatKind::TupleStruct(_, None) | PatKind::Path(..) | PatKind::QPath(..) | PatKind::Lit(..) | @@ -116,8 +115,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(pat.id, &[subpat_exit]) } - PatKind::TupleStruct(_, Some(ref subpats)) | - PatKind::Tup(ref subpats) => { + PatKind::TupleStruct(_, ref subpats, _) | + PatKind::Tuple(ref subpats, _) => { let pats_exit = self.pats_all(subpats.iter(), pred); self.add_ast_node(pat.id, &[pats_exit]) } diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 58f1006f98e6..641fe5f3b474 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -923,9 +923,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { sub.map(|x| folder.fold_pat(x))) } PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)), - PatKind::TupleStruct(pth, pats) => { + PatKind::TupleStruct(pth, pats, ddpos) => { PatKind::TupleStruct(folder.fold_path(pth), - pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) + pats.move_map(|x| folder.fold_pat(x)), ddpos) } PatKind::Path(pth) => { PatKind::Path(folder.fold_path(pth)) @@ -948,7 +948,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { }); PatKind::Struct(pth, fs, etc) } - PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))), + PatKind::Tuple(elts, ddpos) => { + PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos) + } PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)), PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl), PatKind::Range(e1, e2) => { diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 4de876adc1fa..80918ce68e26 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -453,11 +453,9 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { match pattern.node { - PatKind::TupleStruct(ref path, ref opt_children) => { + PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); - if let Some(ref children) = *opt_children { - walk_list!(visitor, visit_pat, children); - } + walk_list!(visitor, visit_pat, children); } PatKind::Path(ref path) => { visitor.visit_path(path, pattern.id); @@ -473,7 +471,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_pat(&field.node.pat) } } - PatKind::Tup(ref tuple_elements) => { + PatKind::Tuple(ref tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); } PatKind::Box(ref subpattern) | diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6b0021f70f08..ea9a76d982a3 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -877,10 +877,10 @@ impl<'a> LoweringContext<'a> { }) } PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), - PatKind::TupleStruct(ref pth, ref pats) => { + PatKind::TupleStruct(ref pth, ref pats, ddpos) => { hir::PatKind::TupleStruct(self.lower_path(pth), - pats.as_ref() - .map(|pats| pats.iter().map(|x| self.lower_pat(x)).collect())) + pats.iter().map(|x| self.lower_pat(x)).collect(), + ddpos) } PatKind::Path(ref pth) => { hir::PatKind::Path(self.lower_path(pth)) @@ -908,8 +908,8 @@ impl<'a> LoweringContext<'a> { .collect(); hir::PatKind::Struct(pth, fs, etc) } - PatKind::Tup(ref elts) => { - hir::PatKind::Tup(elts.iter().map(|x| self.lower_pat(x)).collect()) + PatKind::Tuple(ref elts, ddpos) => { + hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos) } PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), PatKind::Ref(ref inner, mutbl) => { @@ -1855,7 +1855,7 @@ impl<'a> LoweringContext<'a> { let pt = if subpats.is_empty() { hir::PatKind::Path(path) } else { - hir::PatKind::TupleStruct(path, Some(subpats)) + hir::PatKind::TupleStruct(path, subpats, None) }; let pat = self.pat(span, pt); self.resolver.record_resolution(pat.id, def); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index faff8446afcc..3eefe6007b32 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -470,7 +470,7 @@ impl Pat { PatKind::Struct(_, ref fields, _) => { fields.iter().all(|field| field.node.pat.walk_(it)) } - PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => { + PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { s.iter().all(|p| p.walk_(it)) } PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { @@ -485,7 +485,6 @@ impl Pat { PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Ident(_, _, _) | - PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(_, _) => { true @@ -539,9 +538,10 @@ pub enum PatKind { /// The `bool` is `true` in the presence of a `..`. Struct(Path, HirVec>, bool), - /// A tuple struct/variant pattern `Variant(x, y, z)`. - /// "None" means a `Variant(..)` pattern where we don't bind the fields to names. - TupleStruct(Path, Option>>), + /// A tuple struct/variant pattern `Variant(x, y, .., z)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + TupleStruct(Path, HirVec>, Option), /// A path pattern. /// Such pattern can be resolved to a unit struct/variant or a constant. @@ -553,8 +553,10 @@ pub enum PatKind { /// PatKind::Path, and the resolver will have to sort that out. QPath(QSelf, Path), - /// A tuple pattern `(a, b)` - Tup(HirVec>), + /// A tuple pattern `(a, b)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + Tuple(HirVec>, Option), /// A `box` pattern Box(P), /// A reference pattern, e.g. `&mut (a, b)` diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 15f2310607ff..f41c4b0840d5 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -21,6 +21,28 @@ use std::cell::RefCell; pub type PatIdMap = FnvHashMap; +#[derive(Clone, Copy)] +pub struct AjustPos { + gap_pos: usize, + gap_len: usize, +} + +impl FnOnce<(usize,)> for AjustPos { + type Output = usize; + extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize { + if i < self.gap_pos { i } else { i + self.gap_len } + } +} + +// Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and +// pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2). +pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AjustPos { + AjustPos { + gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, + gap_len: expected_len - actual_len, + } +} + // This is used because same-named variables in alternative patterns need to // use the NodeId of their namesake in the first pattern. pub fn pat_id_map(dm: &RefCell, pat: &hir::Pat) -> PatIdMap { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 74bc688d1548..a9ed83d9dc31 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1736,16 +1736,23 @@ impl<'a> State<'a> { None => (), } } - PatKind::TupleStruct(ref path, ref args_) => { + PatKind::TupleStruct(ref path, ref elts, ddpos) => { self.print_path(path, true, 0)?; - match *args_ { - None => word(&mut self.s, "(..)")?, - Some(ref args) => { - self.popen()?; - self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&p))?; - self.pclose()?; + self.popen()?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; + } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; } + } else { + try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))); } + try!(self.pclose()); } PatKind::Path(ref path) => { self.print_path(path, true, 0)?; @@ -1778,11 +1785,23 @@ impl<'a> State<'a> { space(&mut self.s)?; word(&mut self.s, "}")?; } - PatKind::Tup(ref elts) => { + PatKind::Tuple(ref elts, ddpos) => { self.popen()?; - self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; - if elts.len() == 1 { - word(&mut self.s, ",")?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; + } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; + } + } else { + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; + if elts.len() == 1 { + word(&mut self.s, ",")?; + } } self.pclose()?; } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e1fb701e641b..4ecad7f93a5a 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,6 +29,7 @@ #![feature(collections)] #![feature(const_fn)] #![feature(enumset)] +#![feature(fn_traits)] #![feature(iter_arith)] #![feature(libc)] #![feature(nonzero)] @@ -38,6 +39,7 @@ #![feature(slice_patterns)] #![feature(staged_api)] #![feature(question_mark)] +#![feature(unboxed_closures)] #![cfg_attr(test, feature(test))] extern crate arena; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 4cee8c5d89ae..b0add5a23dc4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -1127,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // will visit the substructure recursively. } - PatKind::Wild | PatKind::Tup(..) | PatKind::Box(..) | + PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) | PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Vec(..) => { // Similarly, each of these cases does not diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3999b02425de..da3df7ad3e9a 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -80,6 +80,7 @@ use ty::adjustment; use ty::{self, Ty, TyCtxt}; use hir::{MutImmutable, MutMutable, PatKind}; +use hir::pat_util::pat_adjust_pos; use hir; use syntax::ast; use syntax::codemap::Span; @@ -1225,31 +1226,40 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // _ } - PatKind::TupleStruct(_, None) => { - // variant(..) - } - PatKind::TupleStruct(_, Some(ref subpats)) => { + PatKind::TupleStruct(_, ref subpats, ddpos) => { match opt_def { - Some(Def::Variant(..)) => { + Some(Def::Variant(enum_def, def_id)) => { // variant(x, y, z) + let variant = self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id); + let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + InteriorField(PositionalField(adjust(i)))); self.cat_pattern_(subcmt, &subpat, op)?; } } Some(Def::Struct(..)) => { + let expected_len = match self.pat_ty(&pat) { + Ok(&ty::TyS{sty: ty::TyStruct(adt_def, _), ..}) => { + adt_def.struct_variant().fields.len() + } + ref ty => { + span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty); + } + }; + + let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let cmt_field = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + InteriorField(PositionalField(adjust(i)))); self.cat_pattern_(cmt_field, &subpat, op)?; } } @@ -1284,14 +1294,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - PatKind::Tup(ref subpats) => { + PatKind::Tuple(ref subpats, ddpos) => { // (p1, ..., pN) + let expected_len = match self.pat_ty(&pat) { + Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(), + ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty), + }; + let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + InteriorField(PositionalField(adjust(i)))); self.cat_pattern_(subcmt, &subpat, op)?; } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 56b4036b7d78..6b2c2dfcd72b 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -970,8 +970,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { pats3.iter().any(|p| is_binding_pat(&p)) } - PatKind::TupleStruct(_, Some(ref subpats)) | - PatKind::Tup(ref subpats) => { + PatKind::TupleStruct(_, ref subpats, _) | + PatKind::Tuple(ref subpats, _) => { subpats.iter().any(|p| is_binding_pat(&p)) } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c2db6de03700..50b6d661fa8b 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -33,6 +33,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use hir; use hir::{Item, Generics, StructField, Variant, PatKind}; use hir::intravisit::{self, Visitor}; +use hir::pat_util::pat_adjust_pos; use std::mem::replace; use std::cmp::Ordering; @@ -614,10 +615,10 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, }; match pat.node { // Foo(a, b, c) - // A Variant(..) pattern `PatKind::TupleStruct(_, None)` doesn't have to be recursed into. - PatKind::TupleStruct(_, Some(ref pat_fields)) => { - for (field, struct_field) in pat_fields.iter().zip(&v.fields) { - maybe_do_stability_check(tcx, struct_field.did, field.span, cb) + PatKind::TupleStruct(_, ref pat_fields, ddpos) => { + let adjust = pat_adjust_pos(v.fields.len(), pat_fields.len(), ddpos); + for (i, field) in pat_fields.iter().enumerate() { + maybe_do_stability_check(tcx, v.fields[adjust(i)].did, field.span, cb) } } // Foo { a, b, c } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 2fb5d796589b..f98734f21add 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -374,7 +374,7 @@ fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool { PatKind::Ident(_, _, None) => pat_is_binding(dm, p), PatKind::Ident(_, _, Some(ref s)) => pat_is_catchall(dm, &s), PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s), - PatKind::Tup(ref v) => v.iter().all(|p| pat_is_catchall(dm, &p)), + PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(dm, &p)), _ => false } } @@ -398,7 +398,7 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir: hir::MatchSource::ForLoopDesugar => { // `witnesses[0]` has the form `Some()`, peel off the `Some` let witness = match witnesses[0].node { - PatKind::TupleStruct(_, Some(ref pats)) => match &pats[..] { + PatKind::TupleStruct(_, ref pats, _) => match &pats[..] { [ref pat] => &**pat, _ => bug!(), }, @@ -559,7 +559,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pats_len = pats.len(); let mut pats = pats.into_iter().map(|p| P((*p).clone())); let pat = match left_ty.sty { - ty::TyTuple(_) => PatKind::Tup(pats.collect()), + ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { let v = ctor.variant_for_adt(adt); @@ -580,7 +580,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields) } VariantKind::Tuple => { - PatKind::TupleStruct(def_to_path(cx.tcx, v.did), Some(pats.collect())) + PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None) } VariantKind::Unit => { PatKind::Path(def_to_path(cx.tcx, v.did)) @@ -832,7 +832,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, vec!(Slice(before.len() + after.len())) } }, - PatKind::Box(_) | PatKind::Tup(_) | PatKind::Ref(..) => + PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) => vec!(Single), PatKind::Wild => vec!(), @@ -914,7 +914,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } } - PatKind::TupleStruct(_, ref args) => { + PatKind::TupleStruct(_, ref args, ddpos) => { let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def(); match def { Def::Const(..) | Def::AssociatedConst(..) => @@ -922,10 +922,15 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], been rewritten"), Def::Variant(_, id) if *constructor != Variant(id) => None, Def::Variant(..) | Def::Struct(..) => { - Some(match args { - &Some(ref args) => args.iter().map(|p| &**p).collect(), - &None => vec![DUMMY_WILD_PAT; arity], - }) + match ddpos { + Some(ddpos) => { + let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); + pats.extend(args[ddpos..].iter().map(|p| &**p)); + Some(pats) + } + None => Some(args.iter().map(|p| &**p).collect()) + } } _ => None } @@ -952,7 +957,13 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } } - PatKind::Tup(ref args) => + PatKind::Tuple(ref args, Some(ddpos)) => { + let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); + pats.extend(args[ddpos..].iter().map(|p| &**p)); + Some(pats) + } + PatKind::Tuple(ref args, None) => Some(args.iter().map(|p| &**p).collect()), PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) => diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 9db24fa4770f..b727b778fcd7 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -271,10 +271,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let pat = match expr.node { hir::ExprTup(ref exprs) => - PatKind::Tup(try!(exprs.iter() - .map(|expr| const_expr_to_pat(tcx, &expr, - pat_id, span)) - .collect())), + PatKind::Tuple(try!(exprs.iter() + .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) + .collect()), None), hir::ExprCall(ref callee, ref args) => { let def = *tcx.def_map.borrow().get(&callee.id).unwrap(); @@ -295,7 +294,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span)) .collect()); - PatKind::TupleStruct(path, Some(pats)) + PatKind::TupleStruct(path, pats, None) } hir::ExprStruct(ref path, ref fields, None) => { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 9ab6a437a5ab..2c796690df43 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -31,6 +31,7 @@ #![feature(question_mark)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(type_ascription)] #[macro_use] extern crate syntax; #[macro_use] extern crate log; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 0118b97dd7f3..494d8a5c0356 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -13,7 +13,7 @@ use hair::cx::Cx; use rustc_data_structures::fnv::FnvHashMap; use rustc_const_eval as const_eval; use rustc::hir::def::Def; -use rustc::hir::pat_util::{pat_is_resolved_const, pat_is_binding}; +use rustc::hir::pat_util::{pat_adjust_pos, pat_is_resolved_const, pat_is_binding}; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc::hir::{self, PatKind}; @@ -148,17 +148,24 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } } - PatKind::Tup(ref subpatterns) => { - let subpatterns = - subpatterns.iter() - .enumerate() - .map(|(i, subpattern)| FieldPattern { - field: Field::new(i), - pattern: self.to_pattern(subpattern), - }) - .collect(); + PatKind::Tuple(ref subpatterns, ddpos) => { + match self.cx.tcx.node_id_to_type(pat.id).sty { + ty::TyTuple(ref tys) => { + let adjust = pat_adjust_pos(tys.len(), subpatterns.len(), ddpos); + let subpatterns = + subpatterns.iter() + .enumerate() + .map(|(i, subpattern)| FieldPattern { + field: Field::new(adjust(i)), + pattern: self.to_pattern(subpattern), + }) + .collect(); + + PatternKind::Leaf { subpatterns: subpatterns } + } - PatternKind::Leaf { subpatterns: subpatterns } + ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), + } } PatKind::Ident(bm, ref ident, ref sub) @@ -208,13 +215,21 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { self.variant_or_leaf(pat, vec![]) } - PatKind::TupleStruct(_, ref opt_subpatterns) => { + PatKind::TupleStruct(_, ref subpatterns, ddpos) => { + let pat_ty = self.cx.tcx.node_id_to_type(pat.id); + let adt_def = match pat_ty.sty { + ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, + _ => span_bug!(pat.span, "tuple struct pattern not applied to struct or enum"), + }; + let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); + let variant_def = adt_def.variant_of_def(def); + + let adjust = pat_adjust_pos(variant_def.fields.len(), subpatterns.len(), ddpos); let subpatterns = - opt_subpatterns.iter() - .flat_map(|v| v.iter()) + subpatterns.iter() .enumerate() .map(|(i, field)| FieldPattern { - field: Field::new(i), + field: Field::new(adjust(i)), pattern: self.to_pattern(field), }) .collect(); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index f1e744098b96..953bcf457b80 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,7 +31,7 @@ use std::mem::replace; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::{self, Visitor}; - +use rustc::hir::pat_util::pat_adjust_pos; use rustc::dep_graph::DepNode; use rustc::lint; use rustc::hir::def::{self, Def}; @@ -488,17 +488,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { self.check_field(pattern.span, adt, variant.field_named(field.node.name)); } } - - // Patterns which bind no fields are allowable (the path is check - // elsewhere). - PatKind::TupleStruct(_, Some(ref fields)) => { + PatKind::TupleStruct(_, ref fields, ddpos) => { match self.tcx.pat_ty(pattern).sty { ty::TyStruct(def, _) => { + let adjust = pat_adjust_pos(def.struct_variant().fields.len(), + fields.len(), ddpos); for (i, field) in fields.iter().enumerate() { if let PatKind::Wild = field.node { continue } - self.check_field(field.span, def, &def.struct_variant().fields[i]); + self.check_field(field.span, def, + &def.struct_variant().fields[adjust(i)]); } } ty::TyEnum(..) => { @@ -506,7 +506,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } _ => {} } - } _ => {} } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4fc3abb99332..2444f6acced2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2356,7 +2356,7 @@ impl<'a> Resolver<'a> { } } - PatKind::TupleStruct(ref path, _) | PatKind::Path(ref path) => { + PatKind::TupleStruct(ref path, _, _) | PatKind::Path(ref path) => { // This must be an enum variant, struct or const. let resolution = match self.resolve_possibly_assoc_item(pat_id, None, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 7dba3ef5c67c..05de5d2770d2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -695,7 +695,7 @@ impl<'v> Visitor<'v> for PathCollector { self.collected_paths.push((p.id, path.clone(), ast::Mutability::Mutable, recorder::TypeRef)); } - PatKind::TupleStruct(ref path, _) | + PatKind::TupleStruct(ref path, _, _) | PatKind::Path(ref path) | PatKind::QPath(_, ref path) => { self.collected_paths.push((p.id, path.clone(), diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index dbc277f24326..9b168301f732 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -792,7 +792,7 @@ fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool { m.iter().any(|br| { let pat = br.pats[col]; match pat.node { - PatKind::Tup(_) => true, + PatKind::Tuple(..) => true, PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::Ident(_, _, None) => { match tcx.def_map.borrow().get(&pat.id).unwrap().full_def() { @@ -1833,7 +1833,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = bind_irrefutable_pat(bcx, &inner_pat, val, cleanup_scope); } } - PatKind::TupleStruct(_, ref sub_pats) => { + PatKind::TupleStruct(_, ref sub_pats, ddpos) => { let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def()); match opt_def { Some(Def::Variant(enum_id, var_id)) => { @@ -1843,35 +1843,36 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &repr, Disr::from(vinfo.disr_val), val); - if let Some(ref sub_pat) = *sub_pats { - for (i, &argval) in args.vals.iter().enumerate() { - bcx = bind_irrefutable_pat( - bcx, - &sub_pat[i], - MatchInput::from_val(argval), - cleanup_scope); - } + let adjust = pat_adjust_pos(vinfo.fields.len(), sub_pats.len(), ddpos); + for (i, subpat) in sub_pats.iter().enumerate() { + bcx = bind_irrefutable_pat( + bcx, + subpat, + MatchInput::from_val(args.vals[adjust(i)]), + cleanup_scope); } } Some(Def::Struct(..)) => { - match *sub_pats { - None => { - // This is a unit-like struct. Nothing to do here. + let expected_len = match *ccx.tcx().pat_ty(&pat) { + ty::TyS{sty: ty::TyStruct(adt_def, _), ..} => { + adt_def.struct_variant().fields.len() } - Some(ref elems) => { - // This is the tuple struct case. - let repr = adt::represent_node(bcx, pat.id); - let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in elems.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, - val, Disr(0), i); - bcx = bind_irrefutable_pat( - bcx, - &elem, - MatchInput::from_val(fldptr), - cleanup_scope); - } + ref ty => { + span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty); } + }; + + let adjust = pat_adjust_pos(expected_len, sub_pats.len(), ddpos); + let repr = adt::represent_node(bcx, pat.id); + let val = adt::MaybeSizedValue::sized(val.val); + for (i, elem) in sub_pats.iter().enumerate() { + let fldptr = adt::trans_field_ptr(bcx, &repr, + val, Disr(0), adjust(i)); + bcx = bind_irrefutable_pat( + bcx, + &elem, + MatchInput::from_val(fldptr), + cleanup_scope); } } _ => { @@ -1919,16 +1920,22 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, cleanup_scope); } } - PatKind::Tup(ref elems) => { - let repr = adt::represent_node(bcx, pat.id); - let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in elems.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); - bcx = bind_irrefutable_pat( - bcx, - &elem, - MatchInput::from_val(fldptr), - cleanup_scope); + PatKind::Tuple(ref elems, ddpos) => { + match tcx.node_id_to_type(pat.id).sty { + ty::TyTuple(ref tys) => { + let adjust = pat_adjust_pos(tys.len(), elems.len(), ddpos); + let repr = adt::represent_node(bcx, pat.id); + let val = adt::MaybeSizedValue::sized(val.val); + for (i, elem) in elems.iter().enumerate() { + let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), adjust(i)); + bcx = bind_irrefutable_pat( + bcx, + &elem, + MatchInput::from_val(fldptr), + cleanup_scope); + } + } + ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), } } PatKind::Box(ref inner) => { diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index ba592382d1a7..aec43e69e518 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -318,13 +318,11 @@ fn walk_pattern(cx: &CrateContext, scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); } - PatKind::TupleStruct(_, ref sub_pats_opt) => { + PatKind::TupleStruct(_, ref sub_pats, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - if let Some(ref sub_pats) = *sub_pats_opt { - for p in sub_pats { - walk_pattern(cx, &p, scope_stack, scope_map); - } + for p in sub_pats { + walk_pattern(cx, &p, scope_stack, scope_map); } } @@ -343,7 +341,7 @@ fn walk_pattern(cx: &CrateContext, } } - PatKind::Tup(ref sub_pats) => { + PatKind::Tuple(ref sub_pats, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); for sub_pat in sub_pats { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 10c8ea84bfd6..ce4ac4e815c7 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,7 @@ use hir::def::{self, Def}; use rustc::infer::{self, InferOk, TypeOrigin}; use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; -use hir::pat_util::pat_is_resolved_const; +use hir::pat_util::{pat_adjust_pos, pat_is_resolved_const}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation}; @@ -213,13 +213,13 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { } PatKind::Ident(_, ref path, _) => { let path = hir::Path::from_name(path.span, path.node); - self.check_pat_enum(pat, &path, Some(&[]), expected, false); + self.check_pat_enum(pat, &path, &[], None, expected, false); } - PatKind::TupleStruct(ref path, ref subpats) => { - self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true); + PatKind::TupleStruct(ref path, ref subpats, ddpos) => { + self.check_pat_enum(pat, path, &subpats, ddpos, expected, true); } PatKind::Path(ref path) => { - self.check_pat_enum(pat, path, Some(&[]), expected, false); + self.check_pat_enum(pat, path, &[], None, expected, false); } PatKind::QPath(ref qself, ref path) => { let self_ty = self.to_ty(&qself.ty); @@ -260,14 +260,24 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { PatKind::Struct(ref path, ref fields, etc) => { self.check_pat_struct(pat, path, fields, etc, expected); } - PatKind::Tup(ref elements) => { - let element_tys: Vec<_> = - (0..elements.len()).map(|_| self.next_ty_var()).collect(); + PatKind::Tuple(ref elements, ddpos) => { + let mut expected_len = elements.len(); + if ddpos.is_some() { + // Require known type only when `..` is present + if let ty::TyTuple(ref tys) = + self.structurally_resolved_type(pat.span, expected).sty { + expected_len = tys.len(); + } + } + let max_len = cmp::max(expected_len, elements.len()); + + let element_tys = (0 .. max_len).map(|_| self.next_ty_var()).collect(): Vec<_>; let pat_ty = tcx.mk_tup(element_tys.clone()); self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); - for (element_pat, element_ty) in elements.iter().zip(element_tys) { - self.check_pat(&element_pat, element_ty); + let adjust = pat_adjust_pos(expected_len, elements.len(), ddpos); + for i in 0 .. elements.len() { + self.check_pat(&elements[i], &element_tys[adjust(i)]); } } PatKind::Box(ref inner) => { @@ -615,7 +625,8 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { fn check_pat_enum(&self, pat: &hir::Pat, path: &hir::Path, - subpats: Option<&'gcx [P]>, + subpats: &'gcx [P], + ddpos: Option, expected: Ty<'tcx>, is_tuple_struct_pat: bool) { @@ -628,12 +639,9 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { self.set_tainted_by_errors(); self.write_error(pat.id); - if let Some(subpats) = subpats { - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } + for pat in subpats { + self.check_pat(&pat, tcx.types.err); } - return; } }; @@ -670,15 +678,12 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { }; self.instantiate_path(segments, path_scheme, &ctor_predicates, opt_ty, def, pat.span, pat.id); - let report_bad_struct_kind = |is_warning| { bad_struct_kind_err(tcx.sess, pat, path, is_warning); if is_warning { return; } self.write_error(pat.id); - if let Some(subpats) = subpats { - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } + for pat in subpats { + self.check_pat(&pat, tcx.types.err); } }; @@ -715,11 +720,13 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { }; match (is_tuple_struct_pat, variant.kind()) { - (true, ty::VariantKind::Unit) => { + (true, ty::VariantKind::Unit) if subpats.is_empty() && ddpos.is_some() => { // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) // is allowed for backward compatibility. report_bad_struct_kind(true); } + (true, ty::VariantKind::Unit) | + (false, ty::VariantKind::Tuple) | (_, ty::VariantKind::Struct) => { report_bad_struct_kind(false); return @@ -727,30 +734,23 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { _ => {} } - if let Some(subpats) = subpats { - if subpats.len() == variant.fields.len() { - for (subpat, field) in subpats.iter().zip(&variant.fields) { - let field_ty = self.field_ty(subpat.span, field, expected_substs); - self.check_pat(&subpat, field_ty); - } - } else if variant.fields.is_empty() { - span_err!(tcx.sess, pat.span, E0024, - "this pattern has {} field{}, but the corresponding {} has no fields", - subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name); - - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } - } else { - span_err!(tcx.sess, pat.span, E0023, - "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), if subpats.len() == 1 {""} else {"s"}, - kind_name, - variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); - - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } + let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); + if subpats.len() == variant.fields.len() || + subpats.len() < variant.fields.len() && ddpos.is_some() { + for (i, subpat) in subpats.iter().enumerate() { + let field_ty = self.field_ty(subpat.span, + &variant.fields[adjust(i)], expected_substs); + self.check_pat(&subpat, field_ty); + } + } else { + span_err!(tcx.sess, pat.span, E0023, + "this pattern has {} field{}, but the corresponding {} has {} field{}", + subpats.len(), if subpats.len() == 1 {""} else {"s"}, + kind_name, + variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); + + for pat in subpats { + self.check_pat(&pat, tcx.types.err); } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index b94c9c4ad19c..7598751c8fe1 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -62,31 +62,6 @@ Check how many fields the enum was declared with and ensure that your pattern uses the same number. "##, -E0024: r##" -This error indicates that a pattern attempted to extract the fields of an enum -variant with no fields. Here's a tiny example of this error: - -```compile_fail -// This enum has two variants. -enum Number { - // This variant has no fields. - Zero, - // This variant has one field. - One(u32) -} - -// Assuming x is a Number we can pattern match on its contents. -match x { - Number::Zero(inside) => {}, - Number::One(inside) => {}, -} -``` - -The pattern match `Zero(inside)` is incorrect because the `Zero` variant -contains no fields, yet the `inside` name attempts to bind the first field of -the enum. -"##, - E0025: r##" Each field of a struct can only be bound once in a pattern. Erroneous code example: diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0b23951db366..282b7582393e 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,11 +77,12 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(iter_arith)] +#![feature(question_mark)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(question_mark)] +#![feature(type_ascription)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ca138168b295..4831ee9a2e04 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2579,7 +2579,7 @@ fn name_from_pat(p: &hir::Pat) -> String { match p.node { PatKind::Wild => "_".to_string(), PatKind::Ident(_, ref p, _) => p.node.to_string(), - PatKind::TupleStruct(ref p, _) | PatKind::Path(ref p) => path_to_string(p), + PatKind::TupleStruct(ref p, _, _) | PatKind::Path(ref p) => path_to_string(p), PatKind::QPath(..) => panic!("tried to get argument name from PatKind::QPath, \ which is not allowed in function arguments"), PatKind::Struct(ref name, ref fields, etc) => { @@ -2590,7 +2590,7 @@ fn name_from_pat(p: &hir::Pat) -> String { if etc { ", ..." } else { "" } ) }, - PatKind::Tup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) + PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) .collect::>().join(", ")), PatKind::Box(ref p) => name_from_pat(&**p), PatKind::Ref(ref p, _) => name_from_pat(&**p), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index cbd024c5415f..a75a62ac621f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -567,7 +567,7 @@ impl Pat { PatKind::Struct(_, ref fields, _) => { fields.iter().all(|field| field.node.pat.walk(it)) } - PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => { + PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { s.iter().all(|p| p.walk(it)) } PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { @@ -582,7 +582,6 @@ impl Pat { PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Ident(_, _, _) | - PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(_, _) | PatKind::Mac(_) => { @@ -631,9 +630,10 @@ pub enum PatKind { /// The `bool` is `true` in the presence of a `..`. Struct(Path, Vec>, bool), - /// A tuple struct/variant pattern `Variant(x, y, z)`. - /// "None" means a `Variant(..)` pattern where we don't bind the fields to names. - TupleStruct(Path, Option>>), + /// A tuple struct/variant pattern `Variant(x, y, .., z)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + TupleStruct(Path, Vec>, Option), /// A path pattern. /// Such pattern can be resolved to a unit struct/variant or a constant. @@ -645,8 +645,10 @@ pub enum PatKind { /// PatKind::Path, and the resolver will have to sort that out. QPath(QSelf, Path), - /// A tuple pattern `(a, b)` - Tup(Vec>), + /// A tuple pattern `(a, b)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + Tuple(Vec>, Option), /// A `box` pattern Box(P), /// A reference pattern, e.g. `&mut (a, b)` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7958162986cf..3a1cdae9bfbd 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -832,7 +832,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let pat = if subpats.is_empty() { PatKind::Path(path) } else { - PatKind::TupleStruct(path, Some(subpats)) + PatKind::TupleStruct(path, subpats, None) }; self.pat(span, pat) } @@ -842,7 +842,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.pat(span, pat) } fn pat_tuple(&self, span: Span, pats: Vec>) -> P { - self.pat(span, PatKind::Tup(pats)) + self.pat(span, PatKind::Tuple(pats, None)) } fn pat_some(&self, span: Span, pat: P) -> P { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dbef06f7aa49..5687099b27ce 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -274,7 +274,10 @@ declare_features! ( (active, drop_types_in_const, "1.9.0", Some(33156)), // Allows cfg(target_has_atomic = "..."). - (active, cfg_target_has_atomic, "1.9.0", Some(32976)) + (active, cfg_target_has_atomic, "1.9.0", Some(32976)), + + // Allows `..` in tuple (struct) patterns + (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)) ); declare_features! ( @@ -315,7 +318,6 @@ declare_features! ( // Allows `#[deprecated]` attribute (accepted, deprecated, "1.9.0", Some(29935)) ); - // (changing above list without updating src/doc/reference.md makes @cmr sad) #[derive(PartialEq, Copy, Clone, Debug)] @@ -1024,6 +1026,24 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { pattern.span, "box pattern syntax is experimental"); } + PatKind::Tuple(_, ddpos) + if ddpos.is_some() => { + gate_feature_post!(&self, dotdot_in_tuple_patterns, + pattern.span, + "`..` in tuple patterns is experimental"); + } + PatKind::TupleStruct(_, ref fields, ddpos) + if ddpos.is_some() && !fields.is_empty() => { + gate_feature_post!(&self, dotdot_in_tuple_patterns, + pattern.span, + "`..` in tuple struct patterns is experimental"); + } + PatKind::TupleStruct(_, ref fields, ddpos) + if ddpos.is_none() && fields.is_empty() => { + self.context.span_handler.struct_span_err(pattern.span, + "nullary enum variants are written with \ + no trailing `( )`").emit(); + } _ => {} } visit::walk_pat(self, pattern) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 063e485b153b..edf418e33325 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1084,9 +1084,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { sub.map(|x| folder.fold_pat(x))) } PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)), - PatKind::TupleStruct(pth, pats) => { + PatKind::TupleStruct(pth, pats, ddpos) => { PatKind::TupleStruct(folder.fold_path(pth), - pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) + pats.move_map(|x| folder.fold_pat(x)), ddpos) } PatKind::Path(pth) => { PatKind::Path(folder.fold_path(pth)) @@ -1107,7 +1107,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { }); PatKind::Struct(pth, fs, etc) } - PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))), + PatKind::Tuple(elts, ddpos) => { + PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos) + } PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)), PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl), PatKind::Range(e1, e2) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e25a4eece921..7694f3aa0489 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -954,25 +954,6 @@ impl<'a> Parser<'a> { Ok(result) } - /// Parse a sequence parameter of enum variant. For consistency purposes, - /// these should not be empty. - pub fn parse_enum_variant_seq(&mut self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: F) - -> PResult<'a, Vec> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { - let result = self.parse_unspanned_seq(bra, ket, sep, f)?; - if result.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, - "nullary enum variants are written with no trailing `( )`"); - } - Ok(result) - } - // NB: Do not use this function unless you actually plan to place the // spanned list in the AST. pub fn parse_seq(&mut self, @@ -3436,21 +3417,29 @@ impl<'a> Parser<'a> { }; } - fn parse_pat_tuple_elements(&mut self) -> PResult<'a, Vec>> { + fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool) + -> PResult<'a, (Vec>, Option)> { let mut fields = vec![]; - if !self.check(&token::CloseDelim(token::Paren)) { - fields.push(self.parse_pat()?); - if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { - while self.eat(&token::Comma) && - !self.check(&token::CloseDelim(token::Paren)) { + let mut ddpos = None; + + while !self.check(&token::CloseDelim(token::Paren)) { + if ddpos.is_none() && self.eat(&token::DotDot) { + ddpos = Some(fields.len()); + if self.eat(&token::Comma) { + // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. fields.push(self.parse_pat()?); } + } else { + fields.push(self.parse_pat()?); } - if fields.len() == 1 { + + if !self.check(&token::CloseDelim(token::Paren)) || + (unary_needs_comma && fields.len() == 1 && ddpos.is_none()) { self.expect(&token::Comma)?; } } - Ok(fields) + + Ok((fields, ddpos)) } fn parse_pat_vec_elements( @@ -3629,9 +3618,9 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => { // Parse (pat,pat,pat,...) as tuple pattern self.bump(); - let fields = self.parse_pat_tuple_elements()?; + let (fields, ddpos) = self.parse_pat_tuple_elements(true)?; self.expect(&token::CloseDelim(token::Paren))?; - pat = PatKind::Tup(fields); + pat = PatKind::Tuple(fields, ddpos); } token::OpenDelim(token::Bracket) => { // Parse [pat,pat,...] as slice pattern @@ -3716,20 +3705,10 @@ impl<'a> Parser<'a> { return Err(self.fatal("unexpected `(` after qualified path")); } // Parse tuple struct or enum pattern - if self.look_ahead(1, |t| *t == token::DotDot) { - // This is a "top constructor only" pat - self.bump(); - self.bump(); - self.expect(&token::CloseDelim(token::Paren))?; - pat = PatKind::TupleStruct(path, None); - } else { - let args = self.parse_enum_variant_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| p.parse_pat())?; - pat = PatKind::TupleStruct(path, Some(args)); - } + self.bump(); + let (fields, ddpos) = self.parse_pat_tuple_elements(false)?; + self.expect(&token::CloseDelim(token::Paren))?; + pat = PatKind::TupleStruct(path, fields, ddpos) } _ => { pat = match qself { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 9e899395b6cd..5b9ec924de95 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2467,17 +2467,23 @@ impl<'a> State<'a> { None => () } } - PatKind::TupleStruct(ref path, ref args_) => { + PatKind::TupleStruct(ref path, ref elts, ddpos) => { self.print_path(path, true, 0)?; - match *args_ { - None => word(&mut self.s, "(..)")?, - Some(ref args) => { - self.popen()?; - self.commasep(Inconsistent, &args[..], - |s, p| s.print_pat(&p))?; - self.pclose()?; + self.popen()?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; + } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; } + } else { + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; } + self.pclose()?; } PatKind::Path(ref path) => { self.print_path(path, true, 0)?; @@ -2508,13 +2514,23 @@ impl<'a> State<'a> { space(&mut self.s)?; word(&mut self.s, "}")?; } - PatKind::Tup(ref elts) => { + PatKind::Tuple(ref elts, ddpos) => { self.popen()?; - self.commasep(Inconsistent, - &elts[..], - |s, p| s.print_pat(&p))?; - if elts.len() == 1 { - word(&mut self.s, ",")?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; + } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; + } + } else { + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; + if elts.len() == 1 { + word(&mut self.s, ",")?; + } } self.pclose()?; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a00a5adfb826..a1d8e056b025 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -402,11 +402,9 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { match pattern.node { - PatKind::TupleStruct(ref path, ref opt_children) => { + PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); - if let Some(ref children) = *opt_children { - walk_list!(visitor, visit_pat, children); - } + walk_list!(visitor, visit_pat, children); } PatKind::Path(ref path) => { visitor.visit_path(path, pattern.id); @@ -422,7 +420,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_pat(&field.node.pat) } } - PatKind::Tup(ref tuple_elements) => { + PatKind::Tuple(ref tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); } PatKind::Box(ref subpattern) | diff --git a/src/test/compile-fail/issue-32004.rs b/src/test/compile-fail/issue-32004.rs index 0227a80fd75d..8d74154655fc 100644 --- a/src/test/compile-fail/issue-32004.rs +++ b/src/test/compile-fail/issue-32004.rs @@ -18,12 +18,12 @@ struct S; fn main() { match Foo::Baz { Foo::Bar => {} - //~^ ERROR this pattern has 0 fields, but the corresponding variant + //~^ ERROR `Foo::Bar` does not name a tuple variant or a tuple struct _ => {} } match S { S(()) => {} - //~^ ERROR this pattern has 1 field, but the corresponding struct + //~^ ERROR `S` does not name a tuple variant or a tuple struct } } diff --git a/src/test/compile-fail/match-pattern-field-mismatch-2.rs b/src/test/compile-fail/match-pattern-field-mismatch-2.rs index e63ddf6c7fd9..a4ba93ea1733 100644 --- a/src/test/compile-fail/match-pattern-field-mismatch-2.rs +++ b/src/test/compile-fail/match-pattern-field-mismatch-2.rs @@ -20,7 +20,7 @@ fn main() { color::rgb(_, _, _) => { } color::cmyk(_, _, _, _) => { } color::no_color(_) => { } - //~^ ERROR this pattern has 1 field, but the corresponding variant has no fields + //~^ ERROR `color::no_color` does not name a tuple variant or a tuple struct } } } diff --git a/src/test/compile-fail/pat-tuple-bad-type.rs b/src/test/compile-fail/pat-tuple-bad-type.rs new file mode 100644 index 000000000000..0d50a30dd052 --- /dev/null +++ b/src/test/compile-fail/pat-tuple-bad-type.rs @@ -0,0 +1,27 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn main() { + let x; + + match x { + (..) => {} //~ ERROR the type of this value must be known in this context + _ => {} + } + + match 0u8 { + (..) => {} //~ ERROR mismatched types + _ => {} + } + + x = 10; +} diff --git a/src/test/compile-fail/pat-tuple-feature-gate.rs b/src/test/compile-fail/pat-tuple-feature-gate.rs new file mode 100644 index 000000000000..55ca05bdef38 --- /dev/null +++ b/src/test/compile-fail/pat-tuple-feature-gate.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + match 0 { + (..) => {} //~ ERROR `..` in tuple patterns is experimental + (pat, ..) => {} //~ ERROR `..` in tuple patterns is experimental + S(pat, ..) => {} //~ ERROR `..` in tuple struct patterns is experimental + } +} diff --git a/src/test/compile-fail/pat-tuple-overfield.rs b/src/test/compile-fail/pat-tuple-overfield.rs new file mode 100644 index 000000000000..034ef4a72e21 --- /dev/null +++ b/src/test/compile-fail/pat-tuple-overfield.rs @@ -0,0 +1,28 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +struct S(u8, u8, u8); + +fn main() { + match (1, 2, 3) { + (1, 2, 3, 4) => {} //~ ERROR mismatched types + (1, 2, .., 3, 4) => {} //~ ERROR mismatched types + _ => {} + } + match S(1, 2, 3) { + S(1, 2, 3, 4) => {} + //~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields + S(1, 2, .., 3, 4) => {} + //~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields + _ => {} + } +} diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs index d9f3bb3c40f8..507012e8c5c0 100644 --- a/src/test/compile-fail/pattern-error-continue.rs +++ b/src/test/compile-fail/pattern-error-continue.rs @@ -25,7 +25,7 @@ fn f(_c: char) {} fn main() { match A::B(1, 2) { A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but - A::D(_) => (), //~ ERROR this pattern has 1 field, but + A::D(_) => (), //~ ERROR `A::D` does not name a tuple variant or a tuple struct _ => () } match 'c' { diff --git a/src/test/parse-fail/pat-lt-bracket-6.rs b/src/test/parse-fail/pat-lt-bracket-6.rs index 5ed8f6dee8cd..fb78e558a951 100644 --- a/src/test/parse-fail/pat-lt-bracket-6.rs +++ b/src/test/parse-fail/pat-lt-bracket-6.rs @@ -9,6 +9,5 @@ // except according to those terms. fn main() { - let Test(&desc[..]) = x; //~ error: expected one of `,` or `@`, found `[` - //~^ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[` } diff --git a/src/test/parse-fail/pat-lt-bracket-7.rs b/src/test/parse-fail/pat-lt-bracket-7.rs index 00681e614978..d75589d8889e 100644 --- a/src/test/parse-fail/pat-lt-bracket-7.rs +++ b/src/test/parse-fail/pat-lt-bracket-7.rs @@ -9,6 +9,5 @@ // except according to those terms. fn main() { - for thing(x[]) in foo {} //~ error: expected one of `,` or `@`, found `[` - //~^ ERROR expected one of `@` or `in`, found `[` + for thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[` } diff --git a/src/test/compile-fail/E0024.rs b/src/test/parse-fail/pat-tuple-1.rs similarity index 74% rename from src/test/compile-fail/E0024.rs rename to src/test/parse-fail/pat-tuple-1.rs index 18f4dcf19d70..945d0740654e 100644 --- a/src/test/compile-fail/E0024.rs +++ b/src/test/parse-fail/pat-tuple-1.rs @@ -8,15 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Number { - Zero, - One(u32) -} +// compile-flags: -Z parse-only fn main() { - let x = Number::Zero; - match x { - Number::Zero(inside) => {}, //~ ERROR E0024 - Number::One(inside) => {}, + match 0 { + (, ..) => {} //~ ERROR expected pattern, found `,` } } diff --git a/src/test/parse-fail/pat-tuple-2.rs b/src/test/parse-fail/pat-tuple-2.rs new file mode 100644 index 000000000000..ad52fa578700 --- /dev/null +++ b/src/test/parse-fail/pat-tuple-2.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (pat, ..,) => {} //~ ERROR expected pattern, found `)` + } +} diff --git a/src/test/parse-fail/pat-tuple-3.rs b/src/test/parse-fail/pat-tuple-3.rs new file mode 100644 index 000000000000..95e44ae134c0 --- /dev/null +++ b/src/test/parse-fail/pat-tuple-3.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (.., pat, ..) => {} //~ ERROR expected pattern, found `..` + } +} diff --git a/src/test/parse-fail/pat-tuple-4.rs b/src/test/parse-fail/pat-tuple-4.rs new file mode 100644 index 000000000000..f4c3afa07f10 --- /dev/null +++ b/src/test/parse-fail/pat-tuple-4.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (.. pat) => {} //~ ERROR expected one of `)` or `,`, found `pat` + } +} diff --git a/src/test/parse-fail/pat-tuple-5.rs b/src/test/parse-fail/pat-tuple-5.rs new file mode 100644 index 000000000000..145d1f9d8ec7 --- /dev/null +++ b/src/test/parse-fail/pat-tuple-5.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (pat ..) => {} //~ ERROR expected one of `)`, `,`, or `@`, found `..` + } +} diff --git a/src/test/parse-fail/pat-tuple-6.rs b/src/test/parse-fail/pat-tuple-6.rs new file mode 100644 index 000000000000..3252d92fe1b5 --- /dev/null +++ b/src/test/parse-fail/pat-tuple-6.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (pat) => {} //~ ERROR expected one of `,` or `@`, found `)` + } +} diff --git a/src/test/run-pass/pat-tuple.rs b/src/test/run-pass/pat-tuple.rs new file mode 100644 index 000000000000..ccea068f715a --- /dev/null +++ b/src/test/run-pass/pat-tuple.rs @@ -0,0 +1,202 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn b() { + let x = (1, 2, 3); + match x { + (a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + (.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + (a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn bs() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + S(.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + S(a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn c() { + let x = (1,); + match x { + (2, ..) => panic!(), + (..) => () + } +} + +fn cs() { + struct S(u8); + + let x = S(1); + match x { + S(2, ..) => panic!(), + S(..) => () + } +} + +fn d() { + let x = (1, 2, 3); + let branch = match x { + (1, 1, ..) => 0, + (1, 2, 3, ..) => 1, + (1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn ds() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + let branch = match x { + S(1, 1, ..) => 0, + S(1, 2, 3, ..) => 1, + S(1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn f() { + let x = (1, 2, 3); + match x { + (1, 2, 4) => unreachable!(), + (0, 2, 3, ..) => unreachable!(), + (0, .., 3) => unreachable!(), + (0, ..) => unreachable!(), + (1, 2, 3) => (), + (_, _, _) => unreachable!(), + } + match x { + (..) => (), + } + match x { + (_, _, _, ..) => (), + } + match x { + (a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn fs() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(1, 2, 4) => unreachable!(), + S(0, 2, 3, ..) => unreachable!(), + S(0, .., 3) => unreachable!(), + S(0, ..) => unreachable!(), + S(1, 2, 3) => (), + S(_, _, _) => unreachable!(), + } + match x { + S(..) => (), + } + match x { + S(_, _, _, ..) => (), + } + match x { + S(a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn g() { + struct S; + struct Z; + struct W; + let x = (S, Z, W); + match x { (S, ..) => {} } + match x { (.., W) => {} } + match x { (S, .., W) => {} } + match x { (.., Z, _) => {} } +} + +fn gs() { + struct SS(S, Z, W); + + struct S; + struct Z; + struct W; + let x = SS(S, Z, W); + match x { SS(S, ..) => {} } + match x { SS(.., W) => {} } + match x { SS(S, .., W) => {} } + match x { SS(.., Z, _) => {} } +} + +fn main() { + b(); + bs(); + c(); + cs(); + d(); + ds(); + f(); + fs(); + g(); + gs(); +} From b11f751fedcbbf7ab74207ce345713625ee9f3e1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 159/179] Address review comments --- src/librustc/hir/mod.rs | 4 +- src/librustc/hir/pat_util.rs | 8 +- src/libsyntax/ast.rs | 4 +- src/libsyntax/parse/parser.rs | 4 + src/test/parse-fail/pat-tuple-3.rs | 2 +- src/test/run-pass/pat-tuple-1.rs | 104 +++++++++++++++ src/test/run-pass/pat-tuple-2.rs | 34 +++++ src/test/run-pass/pat-tuple-3.rs | 40 ++++++ src/test/run-pass/pat-tuple-4.rs | 68 ++++++++++ src/test/run-pass/pat-tuple-5.rs | 40 ++++++ src/test/run-pass/pat-tuple-6.rs | 56 ++++++++ src/test/run-pass/pat-tuple.rs | 202 ----------------------------- 12 files changed, 355 insertions(+), 211 deletions(-) create mode 100644 src/test/run-pass/pat-tuple-1.rs create mode 100644 src/test/run-pass/pat-tuple-2.rs create mode 100644 src/test/run-pass/pat-tuple-3.rs create mode 100644 src/test/run-pass/pat-tuple-4.rs create mode 100644 src/test/run-pass/pat-tuple-5.rs create mode 100644 src/test/run-pass/pat-tuple-6.rs delete mode 100644 src/test/run-pass/pat-tuple.rs diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 3eefe6007b32..ea52a393da6c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -539,7 +539,7 @@ pub enum PatKind { Struct(Path, HirVec>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() TupleStruct(Path, HirVec>, Option), @@ -554,7 +554,7 @@ pub enum PatKind { QPath(QSelf, Path), /// A tuple pattern `(a, b)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() Tuple(HirVec>, Option), /// A `box` pattern diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index f41c4b0840d5..cf4842a25d6e 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -22,12 +22,12 @@ use std::cell::RefCell; pub type PatIdMap = FnvHashMap; #[derive(Clone, Copy)] -pub struct AjustPos { +pub struct AdjustPos { gap_pos: usize, gap_len: usize, } -impl FnOnce<(usize,)> for AjustPos { +impl FnOnce<(usize,)> for AdjustPos { type Output = usize; extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize { if i < self.gap_pos { i } else { i + self.gap_len } @@ -36,8 +36,8 @@ impl FnOnce<(usize,)> for AjustPos { // Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and // pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2). -pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AjustPos { - AjustPos { +pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AdjustPos { + AdjustPos { gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, gap_len: expected_len - actual_len, } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a75a62ac621f..9ecaa5b346af 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -631,7 +631,7 @@ pub enum PatKind { Struct(Path, Vec>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() TupleStruct(Path, Vec>, Option), @@ -646,7 +646,7 @@ pub enum PatKind { QPath(QSelf, Path), /// A tuple pattern `(a, b)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() Tuple(Vec>, Option), /// A `box` pattern diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7694f3aa0489..22cc20b8f8c4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3429,6 +3429,10 @@ impl<'a> Parser<'a> { // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. fields.push(self.parse_pat()?); } + } else if ddpos.is_some() && self.eat(&token::DotDot) { + // Emit a friendly error, ignore `..` and continue parsing + self.span_err(self.last_span, "`..` can only be used once per \ + tuple or tuple struct pattern"); } else { fields.push(self.parse_pat()?); } diff --git a/src/test/parse-fail/pat-tuple-3.rs b/src/test/parse-fail/pat-tuple-3.rs index 95e44ae134c0..029dc7a29567 100644 --- a/src/test/parse-fail/pat-tuple-3.rs +++ b/src/test/parse-fail/pat-tuple-3.rs @@ -12,6 +12,6 @@ fn main() { match 0 { - (.., pat, ..) => {} //~ ERROR expected pattern, found `..` + (.., pat, ..) => {} //~ ERROR `..` can only be used once per tuple or tuple struct pattern } } diff --git a/src/test/run-pass/pat-tuple-1.rs b/src/test/run-pass/pat-tuple-1.rs new file mode 100644 index 000000000000..c3796210a8e5 --- /dev/null +++ b/src/test/run-pass/pat-tuple-1.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3); + match x { + (a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + (.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + (a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (a, b, c, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (.., a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn tuple_struct() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + S(.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + S(a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(a, b, c, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(.., a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-2.rs b/src/test/run-pass/pat-tuple-2.rs new file mode 100644 index 000000000000..881e96a9d788 --- /dev/null +++ b/src/test/run-pass/pat-tuple-2.rs @@ -0,0 +1,34 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1,); + match x { + (2, ..) => panic!(), + (..) => () + } +} + +fn tuple_struct() { + struct S(u8); + + let x = S(1); + match x { + S(2, ..) => panic!(), + S(..) => () + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-3.rs b/src/test/run-pass/pat-tuple-3.rs new file mode 100644 index 000000000000..94d33d41899a --- /dev/null +++ b/src/test/run-pass/pat-tuple-3.rs @@ -0,0 +1,40 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3); + let branch = match x { + (1, 1, ..) => 0, + (1, 2, 3, ..) => 1, + (1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn tuple_struct() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + let branch = match x { + S(1, 1, ..) => 0, + S(1, 2, 3, ..) => 1, + S(1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-4.rs b/src/test/run-pass/pat-tuple-4.rs new file mode 100644 index 000000000000..ffd82fea9962 --- /dev/null +++ b/src/test/run-pass/pat-tuple-4.rs @@ -0,0 +1,68 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3); + match x { + (1, 2, 4) => unreachable!(), + (0, 2, 3, ..) => unreachable!(), + (0, .., 3) => unreachable!(), + (0, ..) => unreachable!(), + (1, 2, 3) => (), + (_, _, _) => unreachable!(), + } + match x { + (..) => (), + } + match x { + (_, _, _, ..) => (), + } + match x { + (a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn tuple_struct() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(1, 2, 4) => unreachable!(), + S(0, 2, 3, ..) => unreachable!(), + S(0, .., 3) => unreachable!(), + S(0, ..) => unreachable!(), + S(1, 2, 3) => (), + S(_, _, _) => unreachable!(), + } + match x { + S(..) => (), + } + match x { + S(_, _, _, ..) => (), + } + match x { + S(a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-5.rs b/src/test/run-pass/pat-tuple-5.rs new file mode 100644 index 000000000000..41c4d02abcbd --- /dev/null +++ b/src/test/run-pass/pat-tuple-5.rs @@ -0,0 +1,40 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + struct S; + struct Z; + struct W; + let x = (S, Z, W); + match x { (S, ..) => {} } + match x { (.., W) => {} } + match x { (S, .., W) => {} } + match x { (.., Z, _) => {} } +} + +fn tuple_struct() { + struct SS(S, Z, W); + + struct S; + struct Z; + struct W; + let x = SS(S, Z, W); + match x { SS(S, ..) => {} } + match x { SS(.., W) => {} } + match x { SS(S, .., W) => {} } + match x { SS(.., Z, _) => {} } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-6.rs b/src/test/run-pass/pat-tuple-6.rs new file mode 100644 index 000000000000..6f3f2b3aed55 --- /dev/null +++ b/src/test/run-pass/pat-tuple-6.rs @@ -0,0 +1,56 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3, 4, 5); + match x { + (a, .., b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 4); + assert_eq!(c, 5); + } + } + match x { + (a, b, c, .., d) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + assert_eq!(d, 5); + } + } +} + +fn tuple_struct() { + struct S(u8, u8, u8, u8, u8); + + let x = S(1, 2, 3, 4, 5); + match x { + S(a, .., b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 4); + assert_eq!(c, 5); + } + } + match x { + S(a, b, c, .., d) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + assert_eq!(d, 5); + } + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple.rs b/src/test/run-pass/pat-tuple.rs deleted file mode 100644 index ccea068f715a..000000000000 --- a/src/test/run-pass/pat-tuple.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(dotdot_in_tuple_patterns)] - -fn b() { - let x = (1, 2, 3); - match x { - (a, b, ..) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - } - } - match x { - (.., b, c) => { - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } - match x { - (a, .., c) => { - assert_eq!(a, 1); - assert_eq!(c, 3); - } - } - match x { - (a, b, c) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } -} - -fn bs() { - struct S(u8, u8, u8); - - let x = S(1, 2, 3); - match x { - S(a, b, ..) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - } - } - match x { - S(.., b, c) => { - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } - match x { - S(a, .., c) => { - assert_eq!(a, 1); - assert_eq!(c, 3); - } - } - match x { - S(a, b, c) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } -} - -fn c() { - let x = (1,); - match x { - (2, ..) => panic!(), - (..) => () - } -} - -fn cs() { - struct S(u8); - - let x = S(1); - match x { - S(2, ..) => panic!(), - S(..) => () - } -} - -fn d() { - let x = (1, 2, 3); - let branch = match x { - (1, 1, ..) => 0, - (1, 2, 3, ..) => 1, - (1, 2, ..) => 2, - _ => 3 - }; - assert_eq!(branch, 1); -} - -fn ds() { - struct S(u8, u8, u8); - - let x = S(1, 2, 3); - let branch = match x { - S(1, 1, ..) => 0, - S(1, 2, 3, ..) => 1, - S(1, 2, ..) => 2, - _ => 3 - }; - assert_eq!(branch, 1); -} - -fn f() { - let x = (1, 2, 3); - match x { - (1, 2, 4) => unreachable!(), - (0, 2, 3, ..) => unreachable!(), - (0, .., 3) => unreachable!(), - (0, ..) => unreachable!(), - (1, 2, 3) => (), - (_, _, _) => unreachable!(), - } - match x { - (..) => (), - } - match x { - (_, _, _, ..) => (), - } - match x { - (a, b, c) => { - assert_eq!(1, a); - assert_eq!(2, b); - assert_eq!(3, c); - } - } -} - -fn fs() { - struct S(u8, u8, u8); - - let x = S(1, 2, 3); - match x { - S(1, 2, 4) => unreachable!(), - S(0, 2, 3, ..) => unreachable!(), - S(0, .., 3) => unreachable!(), - S(0, ..) => unreachable!(), - S(1, 2, 3) => (), - S(_, _, _) => unreachable!(), - } - match x { - S(..) => (), - } - match x { - S(_, _, _, ..) => (), - } - match x { - S(a, b, c) => { - assert_eq!(1, a); - assert_eq!(2, b); - assert_eq!(3, c); - } - } -} - -fn g() { - struct S; - struct Z; - struct W; - let x = (S, Z, W); - match x { (S, ..) => {} } - match x { (.., W) => {} } - match x { (S, .., W) => {} } - match x { (.., Z, _) => {} } -} - -fn gs() { - struct SS(S, Z, W); - - struct S; - struct Z; - struct W; - let x = SS(S, Z, W); - match x { SS(S, ..) => {} } - match x { SS(.., W) => {} } - match x { SS(S, .., W) => {} } - match x { SS(.., Z, _) => {} } -} - -fn main() { - b(); - bs(); - c(); - cs(); - d(); - ds(); - f(); - fs(); - g(); - gs(); -} From 7f353a393e76fcee5f56ae3cbee65236433b9fad Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 160/179] Replace pat_adjust_pos with an iterator adapter --- src/librustc/hir/pat_util.rs | 36 +++++++++++++++-------- src/librustc/lib.rs | 2 -- src/librustc/middle/mem_categorization.rs | 20 ++++++------- src/librustc/middle/stability.rs | 7 ++--- src/librustc_const_eval/check_match.rs | 4 +-- src/librustc_const_eval/lib.rs | 1 - src/librustc_mir/hair/cx/pattern.rs | 12 ++++---- src/librustc_privacy/lib.rs | 10 +++---- src/librustc_trans/_match.rs | 17 +++++------ src/librustc_typeck/check/_match.rs | 15 ++++------ src/librustc_typeck/lib.rs | 3 +- 11 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index cf4842a25d6e..1008ba7a6e6a 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -18,28 +18,40 @@ use hir::{self, PatKind}; use syntax::codemap::{respan, Span, Spanned, DUMMY_SP}; use std::cell::RefCell; +use std::iter::{Enumerate, ExactSizeIterator}; pub type PatIdMap = FnvHashMap; -#[derive(Clone, Copy)] -pub struct AdjustPos { +pub struct EnumerateAndAdjust { + enumerate: Enumerate, gap_pos: usize, gap_len: usize, } -impl FnOnce<(usize,)> for AdjustPos { - type Output = usize; - extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize { - if i < self.gap_pos { i } else { i + self.gap_len } +impl Iterator for EnumerateAndAdjust where I: Iterator { + type Item = (usize, ::Item); + + fn next(&mut self) -> Option<(usize, ::Item)> { + self.enumerate.next().map(|(i, elem)| { + (if i < self.gap_pos { i } else { i + self.gap_len }, elem) + }) } } -// Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and -// pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2). -pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AdjustPos { - AdjustPos { - gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, - gap_len: expected_len - actual_len, +pub trait EnumerateAndAdjustIterator { + fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option) + -> EnumerateAndAdjust where Self: Sized; +} + +impl EnumerateAndAdjustIterator for T { + fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option) + -> EnumerateAndAdjust where Self: Sized { + let actual_len = self.len(); + EnumerateAndAdjust { + enumerate: self.enumerate(), + gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, + gap_len: expected_len - actual_len, + } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4ecad7f93a5a..e1fb701e641b 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,7 +29,6 @@ #![feature(collections)] #![feature(const_fn)] #![feature(enumset)] -#![feature(fn_traits)] #![feature(iter_arith)] #![feature(libc)] #![feature(nonzero)] @@ -39,7 +38,6 @@ #![feature(slice_patterns)] #![feature(staged_api)] #![feature(question_mark)] -#![feature(unboxed_closures)] #![cfg_attr(test, feature(test))] extern crate arena; diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index da3df7ad3e9a..e933b22f6079 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -80,7 +80,7 @@ use ty::adjustment; use ty::{self, Ty, TyCtxt}; use hir::{MutImmutable, MutMutable, PatKind}; -use hir::pat_util::pat_adjust_pos; +use hir::pat_util::EnumerateAndAdjustIterator; use hir; use syntax::ast; use syntax::codemap::Span; @@ -1230,15 +1230,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match opt_def { Some(Def::Variant(enum_def, def_id)) => { // variant(x, y, z) - let variant = self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id); - let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); - for (i, subpat) in subpats.iter().enumerate() { + let expected_len = self.tcx().lookup_adt_def(enum_def) + .variant_with_id(def_id).fields.len(); + for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(adjust(i)))); + InteriorField(PositionalField(i))); self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1253,13 +1253,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } }; - let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); - for (i, subpat) in subpats.iter().enumerate() { + for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let cmt_field = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(adjust(i)))); + InteriorField(PositionalField(i))); self.cat_pattern_(cmt_field, &subpat, op)?; } } @@ -1300,13 +1299,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(), ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty), }; - let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); - for (i, subpat) in subpats.iter().enumerate() { + for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(adjust(i)))); + InteriorField(PositionalField(i))); self.cat_pattern_(subcmt, &subpat, op)?; } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 50b6d661fa8b..fcb03aba6d12 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -33,7 +33,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use hir; use hir::{Item, Generics, StructField, Variant, PatKind}; use hir::intravisit::{self, Visitor}; -use hir::pat_util::pat_adjust_pos; +use hir::pat_util::EnumerateAndAdjustIterator; use std::mem::replace; use std::cmp::Ordering; @@ -616,9 +616,8 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, match pat.node { // Foo(a, b, c) PatKind::TupleStruct(_, ref pat_fields, ddpos) => { - let adjust = pat_adjust_pos(v.fields.len(), pat_fields.len(), ddpos); - for (i, field) in pat_fields.iter().enumerate() { - maybe_do_stability_check(tcx, v.fields[adjust(i)].did, field.span, cb) + for (i, field) in pat_fields.iter().enumerate_and_adjust(v.fields.len(), ddpos) { + maybe_do_stability_check(tcx, v.fields[i].did, field.span, cb) } } // Foo { a, b, c } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index f98734f21add..16b61534ee9a 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -924,7 +924,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], Def::Variant(..) | Def::Struct(..) => { match ddpos { Some(ddpos) => { - let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect(); pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); pats.extend(args[ddpos..].iter().map(|p| &**p)); Some(pats) @@ -958,7 +958,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } PatKind::Tuple(ref args, Some(ddpos)) => { - let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect(); pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); pats.extend(args[ddpos..].iter().map(|p| &**p)); Some(pats) diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 2c796690df43..9ab6a437a5ab 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -31,7 +31,6 @@ #![feature(question_mark)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(type_ascription)] #[macro_use] extern crate syntax; #[macro_use] extern crate log; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 494d8a5c0356..b9ba860e8d0a 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -13,7 +13,7 @@ use hair::cx::Cx; use rustc_data_structures::fnv::FnvHashMap; use rustc_const_eval as const_eval; use rustc::hir::def::Def; -use rustc::hir::pat_util::{pat_adjust_pos, pat_is_resolved_const, pat_is_binding}; +use rustc::hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const, pat_is_binding}; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc::hir::{self, PatKind}; @@ -151,12 +151,11 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::Tuple(ref subpatterns, ddpos) => { match self.cx.tcx.node_id_to_type(pat.id).sty { ty::TyTuple(ref tys) => { - let adjust = pat_adjust_pos(tys.len(), subpatterns.len(), ddpos); let subpatterns = subpatterns.iter() - .enumerate() + .enumerate_and_adjust(tys.len(), ddpos) .map(|(i, subpattern)| FieldPattern { - field: Field::new(adjust(i)), + field: Field::new(i), pattern: self.to_pattern(subpattern), }) .collect(); @@ -224,12 +223,11 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); let variant_def = adt_def.variant_of_def(def); - let adjust = pat_adjust_pos(variant_def.fields.len(), subpatterns.len(), ddpos); let subpatterns = subpatterns.iter() - .enumerate() + .enumerate_and_adjust(variant_def.fields.len(), ddpos) .map(|(i, field)| FieldPattern { - field: Field::new(adjust(i)), + field: Field::new(i), pattern: self.to_pattern(field), }) .collect(); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 953bcf457b80..c90d152e3c31 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,7 +31,7 @@ use std::mem::replace; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::{self, Visitor}; -use rustc::hir::pat_util::pat_adjust_pos; +use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::dep_graph::DepNode; use rustc::lint; use rustc::hir::def::{self, Def}; @@ -491,14 +491,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { PatKind::TupleStruct(_, ref fields, ddpos) => { match self.tcx.pat_ty(pattern).sty { ty::TyStruct(def, _) => { - let adjust = pat_adjust_pos(def.struct_variant().fields.len(), - fields.len(), ddpos); - for (i, field) in fields.iter().enumerate() { + let expected_len = def.struct_variant().fields.len(); + for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) { if let PatKind::Wild = field.node { continue } - self.check_field(field.span, def, - &def.struct_variant().fields[adjust(i)]); + self.check_field(field.span, def, &def.struct_variant().fields[i]); } } ty::TyEnum(..) => { diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 9b168301f732..4b22e410f4c2 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -1843,12 +1843,12 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &repr, Disr::from(vinfo.disr_val), val); - let adjust = pat_adjust_pos(vinfo.fields.len(), sub_pats.len(), ddpos); - for (i, subpat) in sub_pats.iter().enumerate() { + for (i, subpat) in sub_pats.iter() + .enumerate_and_adjust(vinfo.fields.len(), ddpos) { bcx = bind_irrefutable_pat( bcx, subpat, - MatchInput::from_val(args.vals[adjust(i)]), + MatchInput::from_val(args.vals[i]), cleanup_scope); } } @@ -1862,12 +1862,10 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } }; - let adjust = pat_adjust_pos(expected_len, sub_pats.len(), ddpos); let repr = adt::represent_node(bcx, pat.id); let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in sub_pats.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, - val, Disr(0), adjust(i)); + for (i, elem) in sub_pats.iter().enumerate_and_adjust(expected_len, ddpos) { + let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); bcx = bind_irrefutable_pat( bcx, &elem, @@ -1923,11 +1921,10 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, PatKind::Tuple(ref elems, ddpos) => { match tcx.node_id_to_type(pat.id).sty { ty::TyTuple(ref tys) => { - let adjust = pat_adjust_pos(tys.len(), elems.len(), ddpos); let repr = adt::represent_node(bcx, pat.id); let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in elems.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), adjust(i)); + for (i, elem) in elems.iter().enumerate_and_adjust(tys.len(), ddpos) { + let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); bcx = bind_irrefutable_pat( bcx, &elem, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ce4ac4e815c7..693703c7236e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,7 @@ use hir::def::{self, Def}; use rustc::infer::{self, InferOk, TypeOrigin}; use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; -use hir::pat_util::{pat_adjust_pos, pat_is_resolved_const}; +use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation}; @@ -271,13 +271,12 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { } let max_len = cmp::max(expected_len, elements.len()); - let element_tys = (0 .. max_len).map(|_| self.next_ty_var()).collect(): Vec<_>; + let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect(); let pat_ty = tcx.mk_tup(element_tys.clone()); self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); - let adjust = pat_adjust_pos(expected_len, elements.len(), ddpos); - for i in 0 .. elements.len() { - self.check_pat(&elements[i], &element_tys[adjust(i)]); + for (i, elem) in elements.iter().enumerate_and_adjust(expected_len, ddpos) { + self.check_pat(elem, &element_tys[i]); } } PatKind::Box(ref inner) => { @@ -734,12 +733,10 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { _ => {} } - let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { - for (i, subpat) in subpats.iter().enumerate() { - let field_ty = self.field_ty(subpat.span, - &variant.fields[adjust(i)], expected_substs); + for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { + let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs); self.check_pat(&subpat, field_ty); } } else { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 282b7582393e..0b23951db366 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,12 +77,11 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(iter_arith)] -#![feature(question_mark)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(type_ascription)] +#![feature(question_mark)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; From 726f05c73c032efa5e41f0de44ccc38dfbfb6acd Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 May 2016 11:26:03 +0300 Subject: [PATCH 161/179] Do not forget to schedule the drop for the argument --- src/librustc_trans/base.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ddfa08516e59..712805061ea8 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1660,8 +1660,8 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { self.schedule_drop_mem(arg_scope_id, llarg, arg_ty, None); datum::Datum::new(llarg, - arg_ty, - datum::Lvalue::new("FunctionContext::bind_args")) + arg_ty, + datum::Lvalue::new("FunctionContext::bind_args")) } else { let lltmp = if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { let lltemp = alloc_ty(bcx, arg_ty, ""); @@ -1683,6 +1683,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { // And coerce the temporary into the type we expect. b.pointercast(lltemp, arg.memory_ty(bcx.ccx()).ptr_to()) }; + bcx.fcx.schedule_drop_mem(arg_scope_id, lltmp, arg_ty, None); datum::Datum::new(lltmp, arg_ty, datum::Lvalue::new("bind_args")) } From d875a9528636772f0008997437d1ef6d272aa156 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Thu, 26 May 2016 10:54:58 +0200 Subject: [PATCH 162/179] Extend the test for `EscapeUnicode` to also check that it is legitimately an `ExactSizeIterator`. --- src/libcoretest/char.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index f5d014fe8018..73943407b9f9 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -278,6 +278,12 @@ fn eu_iterator_specializations() { // Check last assert_eq!(iter.clone().last(), Some('}')); + // Check len + assert_eq!(iter.len(), len - offset); + + // Check size_hint (= len in ExactSizeIterator) + assert_eq!(iter.size_hint(), (iter.len(), Some(iter.len()))); + // Check counting assert_eq!(iter.clone().count(), len - offset); From 42ee0f0d45e4beff93551f14480c138c6ab8bc0c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 26 May 2016 12:41:40 +0300 Subject: [PATCH 163/179] Fix stores codegen pass --- src/test/codegen/stores.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index f849a6c9b18b..8c425507975c 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -26,8 +26,8 @@ pub struct Bytes { #[no_mangle] #[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { -// CHECK: [[VAR:%[0-9]+]] = bitcast [4 x i8]* %y to i32* -// CHECK: store i32 %{{.*}}, i32* [[VAR]], align 1 +// CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 1 +// CHECK: [[VAR:%[0-9]+]] = bitcast i32* %{{.*}} to [4 x i8]* *x = y; } @@ -37,7 +37,7 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { #[no_mangle] #[rustc_no_mir] // FIXME #27840 MIR has different codegen. pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { -// CHECK: [[VAR:%[0-9]+]] = bitcast %Bytes* %y to i32* -// CHECK: store i32 %{{.*}}, i32* [[VAR]], align 1 +// CHECK: store i32 %{{.*}}, i32* %{{.*}}, align 1 +// CHECK: [[VAR:%[0-9]+]] = bitcast i32* %{{.*}} to %Bytes* *x = y; } From 9c84a1107c6495acc08f2393cc749599c5ad37a1 Mon Sep 17 00:00:00 2001 From: Alexander Polyakov Date: Thu, 26 May 2016 22:38:33 +0300 Subject: [PATCH 164/179] Make Ipv4Addr cmp() faster --- src/libstd/net/ip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 45b85d600a65..ba485f819f88 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -251,7 +251,7 @@ impl PartialOrd for Ipv4Addr { #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Ipv4Addr { fn cmp(&self, other: &Ipv4Addr) -> Ordering { - self.octets().cmp(&other.octets()) + ntoh(self.inner.s_addr).cmp(&ntoh(other.inner.s_addr)) } } From fc2b24500f18fe5a661c3a5057408b8f7e7ec937 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 165/179] Fix overflow in type checking of tuple patterns --- src/librustc_typeck/check/_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 693703c7236e..9030a6f222b8 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -275,7 +275,7 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { let pat_ty = tcx.mk_tup(element_tys.clone()); self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); - for (i, elem) in elements.iter().enumerate_and_adjust(expected_len, ddpos) { + for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, &element_tys[i]); } } From d74f410187de2d75e3b0d376c0b08497d32b7d50 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 18 May 2016 07:25:44 +0000 Subject: [PATCH 166/179] Add and use `HasAttrs` trait --- src/libsyntax/ast.rs | 25 ++------ src/libsyntax/attr.rs | 141 +++++++++++++++++++++++++----------------- 2 files changed, 89 insertions(+), 77 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9ecaa5b346af..c8ded115db86 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -15,7 +15,7 @@ pub use self::UnsafeSource::*; pub use self::ViewPath_::*; pub use self::PathParameters::*; -use attr::ThinAttributes; +use attr::{ThinAttributes, HasAttrs}; use codemap::{mk_sp, respan, Span, Spanned, DUMMY_SP, ExpnId}; use abi::Abi; use errors; @@ -831,13 +831,7 @@ impl StmtKind { } pub fn attrs(&self) -> &[Attribute] { - match *self { - StmtKind::Decl(ref d, _) => d.attrs(), - StmtKind::Expr(ref e, _) | - StmtKind::Semi(ref e, _) => e.attrs(), - StmtKind::Mac(_, _, Some(ref b)) => b, - StmtKind::Mac(_, _, None) => &[], - } + HasAttrs::attrs(self) } } @@ -870,10 +864,7 @@ pub struct Local { impl Local { pub fn attrs(&self) -> &[Attribute] { - match self.attrs { - Some(ref b) => b, - None => &[], - } + HasAttrs::attrs(self) } } @@ -889,10 +880,7 @@ pub enum DeclKind { impl Decl { pub fn attrs(&self) -> &[Attribute] { - match self.node { - DeclKind::Local(ref l) => l.attrs(), - DeclKind::Item(ref i) => i.attrs(), - } + HasAttrs::attrs(self) } } @@ -937,10 +925,7 @@ pub struct Expr { impl Expr { pub fn attrs(&self) -> &[Attribute] { - match self.attrs { - Some(ref b) => b, - None => &[], - } + HasAttrs::attrs(self) } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 8761ca371789..c3c3deea1877 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -884,82 +884,109 @@ impl AttributesExt for Vec { } } +pub trait HasAttrs: Sized { + fn attrs(&self) -> &[ast::Attribute]; + fn map_attrs) -> Vec>(self, f: F) -> Self; +} + /// A cheap way to add Attributes to an AST node. pub trait WithAttrs { // FIXME: Could be extended to anything IntoIter fn with_attrs(self, attrs: ThinAttributes) -> Self; } -impl WithAttrs for P { +impl WithAttrs for T { fn with_attrs(self, attrs: ThinAttributes) -> Self { - self.map(|mut e| { - e.attrs.update(|a| a.append(attrs)); - e + self.map_attrs(|mut orig_attrs| { + orig_attrs.extend(attrs.into_attr_vec()); + orig_attrs }) } } -impl WithAttrs for P { - fn with_attrs(self, attrs: ThinAttributes) -> Self { - self.map(|Item { ident, attrs: mut ats, id, node, vis, span }| { - ats.extend(attrs.into_attr_vec()); - Item { - ident: ident, - attrs: ats, - id: id, - node: node, - vis: vis, - span: span, - } - }) +impl HasAttrs for Vec { + fn attrs(&self) -> &[Attribute] { + &self + } + fn map_attrs) -> Vec>(self, f: F) -> Self { + f(self) } } -impl WithAttrs for P { - fn with_attrs(self, attrs: ThinAttributes) -> Self { - self.map(|Local { pat, ty, init, id, span, attrs: mut ats }| { - ats.update(|a| a.append(attrs)); - Local { - pat: pat, - ty: ty, - init: init, - id: id, - span: span, - attrs: ats, - } - }) +impl HasAttrs for ThinAttributes { + fn attrs(&self) -> &[Attribute] { + self.as_attr_slice() + } + fn map_attrs) -> Vec>(self, f: F) -> Self { + self.map_thin_attrs(f) } } -impl WithAttrs for P { - fn with_attrs(self, attrs: ThinAttributes) -> Self { - self.map(|Spanned { span, node }| { - Spanned { - span: span, - node: match node { - DeclKind::Local(local) => DeclKind::Local(local.with_attrs(attrs)), - DeclKind::Item(item) => DeclKind::Item(item.with_attrs(attrs)), - } - } - }) +impl HasAttrs for P { + fn attrs(&self) -> &[Attribute] { + (**self).attrs() + } + fn map_attrs) -> Vec>(self, f: F) -> Self { + self.map(|t| t.map_attrs(f)) } } -impl WithAttrs for P { - fn with_attrs(self, attrs: ThinAttributes) -> Self { - self.map(|Spanned { span, node }| { - Spanned { - span: span, - node: match node { - StmtKind::Decl(decl, id) => StmtKind::Decl(decl.with_attrs(attrs), id), - StmtKind::Expr(expr, id) => StmtKind::Expr(expr.with_attrs(attrs), id), - StmtKind::Semi(expr, id) => StmtKind::Semi(expr.with_attrs(attrs), id), - StmtKind::Mac(mac, style, mut ats) => { - ats.update(|a| a.append(attrs)); - StmtKind::Mac(mac, style, ats) - } - }, - } - }) +impl HasAttrs for DeclKind { + fn attrs(&self) -> &[Attribute] { + match *self { + DeclKind::Local(ref local) => local.attrs(), + DeclKind::Item(ref item) => item.attrs(), + } + } + + fn map_attrs) -> Vec>(self, f: F) -> Self { + match self { + DeclKind::Local(local) => DeclKind::Local(local.map_attrs(f)), + DeclKind::Item(item) => DeclKind::Item(item.map_attrs(f)), + } } } + +impl HasAttrs for StmtKind { + fn attrs(&self) -> &[Attribute] { + match *self { + StmtKind::Decl(ref decl, _) => decl.attrs(), + StmtKind::Expr(ref expr, _) | StmtKind::Semi(ref expr, _) => expr.attrs(), + StmtKind::Mac(_, _, ref attrs) => attrs.attrs(), + } + } + + fn map_attrs) -> Vec>(self, f: F) -> Self { + match self { + StmtKind::Decl(decl, id) => StmtKind::Decl(decl.map_attrs(f), id), + StmtKind::Expr(expr, id) => StmtKind::Expr(expr.map_attrs(f), id), + StmtKind::Semi(expr, id) => StmtKind::Semi(expr.map_attrs(f), id), + StmtKind::Mac(mac, style, attrs) => + StmtKind::Mac(mac, style, attrs.map_attrs(f)), + } + } +} + +macro_rules! derive_has_attrs_from_field { + ($($ty:path),*) => { derive_has_attrs_from_field!($($ty: .attrs),*); }; + ($($ty:path : $(.$field:ident)*),*) => { $( + impl HasAttrs for $ty { + fn attrs(&self) -> &[Attribute] { + self $(.$field)* .attrs() + } + + fn map_attrs(mut self, f: F) -> Self + where F: FnOnce(Vec) -> Vec, + { + self $(.$field)* = self $(.$field)* .map_attrs(f); + self + } + } + )* } +} + +derive_has_attrs_from_field! { + Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm +} + +derive_has_attrs_from_field! { Decl: .node, Stmt: .node, ast::Variant: .node.attrs } From f6a4ecfba76464034887a1303250dad661dd66a9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 15 May 2016 02:34:32 +0000 Subject: [PATCH 167/179] Refactor the `syntax::config::fold_*` functions into methods --- src/libsyntax/config.rs | 228 ++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 147 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 4554a280e5f1..0491a8c54942 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -50,11 +50,71 @@ pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { - fold_foreign_mod(self, foreign_mod) + ast::ForeignMod { + abi: foreign_mod.abi, + items: foreign_mod.items.into_iter().filter(|item| { + (self.in_cfg)(&item.attrs) + }).collect(), + } } + fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { - fold_item_kind(self, item) + let fold_struct = |this: &mut Self, vdata| match vdata { + ast::VariantData::Struct(fields, id) => { + ast::VariantData::Struct(fields.into_iter().filter(|m| { + (this.in_cfg)(&m.attrs) + }).collect(), id) + } + ast::VariantData::Tuple(fields, id) => { + ast::VariantData::Tuple(fields.into_iter().filter(|m| { + (this.in_cfg)(&m.attrs) + }).collect(), id) + } + ast::VariantData::Unit(id) => ast::VariantData::Unit(id) + }; + + let item = match item { + ast::ItemKind::Impl(u, o, a, b, c, impl_items) => { + let impl_items = impl_items.into_iter() + .filter(|ii| (self.in_cfg)(&ii.attrs)) + .collect(); + ast::ItemKind::Impl(u, o, a, b, c, impl_items) + } + ast::ItemKind::Trait(u, a, b, methods) => { + let methods = methods.into_iter() + .filter(|ti| (self.in_cfg)(&ti.attrs)) + .collect(); + ast::ItemKind::Trait(u, a, b, methods) + } + ast::ItemKind::Struct(def, generics) => { + ast::ItemKind::Struct(fold_struct(self, def), generics) + } + ast::ItemKind::Enum(def, generics) => { + let variants = def.variants.into_iter().filter_map(|v| { + if !(self.in_cfg)(&v.node.attrs) { + None + } else { + Some(Spanned { + node: ast::Variant_ { + name: v.node.name, + attrs: v.node.attrs, + data: fold_struct(self, v.node.data), + disr_expr: v.node.disr_expr, + }, + span: v.span + }) + } + }); + ast::ItemKind::Enum(ast::EnumDef { + variants: variants.collect(), + }, generics) + } + item => item, + }; + + fold::noop_fold_item_kind(item, self) } + fn fold_expr(&mut self, expr: P) -> P { // If an expr is valid to cfg away it will have been removed by the // outer stmt or expression folder before descending in here. @@ -69,17 +129,33 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } fold_expr(self, expr) } + fn fold_opt_expr(&mut self, expr: P) -> Option> { - fold_opt_expr(self, expr) + if (self.in_cfg)(expr.attrs()) { + Some(fold_expr(self, expr)) + } else { + None + } } + fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { - fold_stmt(self, stmt) + if (self.in_cfg)(stmt.node.attrs()) { + fold::noop_fold_stmt(stmt, self) + } else { + SmallVector::zero() + } } + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { fold::noop_fold_mac(mac, self) } + fn fold_item(&mut self, item: P) -> SmallVector> { - fold_item(self, item) + if (self.in_cfg)(&item.attrs) { + SmallVector::one(item.map(|i| self.fold_item_simple(i))) + } else { + SmallVector::zero() + } } } @@ -94,114 +170,6 @@ pub fn strip_items<'a, F>(diagnostic: &'a Handler, ctxt.fold_crate(krate) } -fn filter_foreign_item(cx: &mut Context, - item: ast::ForeignItem) - -> Option where - F: FnMut(&[ast::Attribute]) -> bool -{ - if foreign_item_in_cfg(cx, &item) { - Some(item) - } else { - None - } -} - -fn fold_foreign_mod(cx: &mut Context, - ast::ForeignMod {abi, items}: ast::ForeignMod) - -> ast::ForeignMod where - F: FnMut(&[ast::Attribute]) -> bool -{ - ast::ForeignMod { - abi: abi, - items: items.into_iter() - .filter_map(|a| filter_foreign_item(cx, a)) - .collect() - } -} - -fn fold_item(cx: &mut Context, item: P) -> SmallVector> where - F: FnMut(&[ast::Attribute]) -> bool -{ - if item_in_cfg(cx, &item) { - SmallVector::one(item.map(|i| cx.fold_item_simple(i))) - } else { - SmallVector::zero() - } -} - -fn fold_item_kind(cx: &mut Context, item: ast::ItemKind) -> ast::ItemKind where - F: FnMut(&[ast::Attribute]) -> bool -{ - let item = match item { - ast::ItemKind::Impl(u, o, a, b, c, impl_items) => { - let impl_items = impl_items.into_iter() - .filter(|ii| (cx.in_cfg)(&ii.attrs)) - .collect(); - ast::ItemKind::Impl(u, o, a, b, c, impl_items) - } - ast::ItemKind::Trait(u, a, b, methods) => { - let methods = methods.into_iter() - .filter(|ti| (cx.in_cfg)(&ti.attrs)) - .collect(); - ast::ItemKind::Trait(u, a, b, methods) - } - ast::ItemKind::Struct(def, generics) => { - ast::ItemKind::Struct(fold_struct(cx, def), generics) - } - ast::ItemKind::Enum(def, generics) => { - let variants = def.variants.into_iter().filter_map(|v| { - if !(cx.in_cfg)(&v.node.attrs) { - None - } else { - Some(Spanned { - node: ast::Variant_ { - name: v.node.name, - attrs: v.node.attrs, - data: fold_struct(cx, v.node.data), - disr_expr: v.node.disr_expr, - }, - span: v.span - }) - } - }); - ast::ItemKind::Enum(ast::EnumDef { - variants: variants.collect(), - }, generics) - } - item => item, - }; - - fold::noop_fold_item_kind(item, cx) -} - -fn fold_struct(cx: &mut Context, vdata: ast::VariantData) -> ast::VariantData where - F: FnMut(&[ast::Attribute]) -> bool -{ - match vdata { - ast::VariantData::Struct(fields, id) => { - ast::VariantData::Struct(fields.into_iter().filter(|m| { - (cx.in_cfg)(&m.attrs) - }).collect(), id) - } - ast::VariantData::Tuple(fields, id) => { - ast::VariantData::Tuple(fields.into_iter().filter(|m| { - (cx.in_cfg)(&m.attrs) - }).collect(), id) - } - ast::VariantData::Unit(id) => ast::VariantData::Unit(id) - } -} - -fn fold_opt_expr(cx: &mut Context, expr: P) -> Option> - where F: FnMut(&[ast::Attribute]) -> bool -{ - if expr_in_cfg(cx, &expr) { - Some(fold_expr(cx, expr)) - } else { - None - } -} - fn fold_expr(cx: &mut Context, expr: P) -> P where F: FnMut(&[ast::Attribute]) -> bool { @@ -222,40 +190,6 @@ fn fold_expr(cx: &mut Context, expr: P) -> P where }) } -fn fold_stmt(cx: &mut Context, stmt: ast::Stmt) -> SmallVector - where F: FnMut(&[ast::Attribute]) -> bool -{ - if stmt_in_cfg(cx, &stmt) { - fold::noop_fold_stmt(stmt, cx) - } else { - SmallVector::zero() - } -} - -fn stmt_in_cfg(cx: &mut Context, stmt: &ast::Stmt) -> bool where - F: FnMut(&[ast::Attribute]) -> bool -{ - (cx.in_cfg)(stmt.node.attrs()) -} - -fn expr_in_cfg(cx: &mut Context, expr: &ast::Expr) -> bool where - F: FnMut(&[ast::Attribute]) -> bool -{ - (cx.in_cfg)(expr.attrs()) -} - -fn item_in_cfg(cx: &mut Context, item: &ast::Item) -> bool where - F: FnMut(&[ast::Attribute]) -> bool -{ - return (cx.in_cfg)(&item.attrs); -} - -fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool where - F: FnMut(&[ast::Attribute]) -> bool -{ - return (cx.in_cfg)(&item.attrs); -} - fn is_cfg(attr: &ast::Attribute) -> bool { attr.check_name("cfg") } From a65b28346d15645af5a953dd8ba3a70d826120dc Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 15 May 2016 09:15:02 +0000 Subject: [PATCH 168/179] Introduce `CfgFolder` trait --- src/libsyntax/config.rs | 51 ++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 0491a8c54942..54f3feee96ca 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -19,6 +19,11 @@ use ptr::P; use util::small_vector::SmallVector; +pub trait CfgFolder: fold::Folder { + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool; + fn visit_unconfigurable_expr(&mut self, _expr: &ast::Expr) {} +} + /// A folder that strips out items that do not belong in the current /// configuration. struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { @@ -26,6 +31,19 @@ struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { diagnostic: &'a Handler, } +impl<'a, F: FnMut(&[ast::Attribute]) -> bool> CfgFolder for Context<'a, F> { + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { + (self.in_cfg)(attrs) + } + + fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) { + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { + let msg = "removing an expression is not supported in this position"; + self.diagnostic.span_err(attr.span, msg); + } + } +} + // Support conditional compilation by transforming the AST, stripping out // any items that do not belong in the current configuration pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, @@ -48,12 +66,12 @@ pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, }) } -impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { +impl fold::Folder for T { fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, items: foreign_mod.items.into_iter().filter(|item| { - (self.in_cfg)(&item.attrs) + self.in_cfg(&item.attrs) }).collect(), } } @@ -62,12 +80,12 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> let fold_struct = |this: &mut Self, vdata| match vdata { ast::VariantData::Struct(fields, id) => { ast::VariantData::Struct(fields.into_iter().filter(|m| { - (this.in_cfg)(&m.attrs) + this.in_cfg(&m.attrs) }).collect(), id) } ast::VariantData::Tuple(fields, id) => { ast::VariantData::Tuple(fields.into_iter().filter(|m| { - (this.in_cfg)(&m.attrs) + this.in_cfg(&m.attrs) }).collect(), id) } ast::VariantData::Unit(id) => ast::VariantData::Unit(id) @@ -76,13 +94,13 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> let item = match item { ast::ItemKind::Impl(u, o, a, b, c, impl_items) => { let impl_items = impl_items.into_iter() - .filter(|ii| (self.in_cfg)(&ii.attrs)) + .filter(|ii| self.in_cfg(&ii.attrs)) .collect(); ast::ItemKind::Impl(u, o, a, b, c, impl_items) } ast::ItemKind::Trait(u, a, b, methods) => { let methods = methods.into_iter() - .filter(|ti| (self.in_cfg)(&ti.attrs)) + .filter(|ti| self.in_cfg(&ti.attrs)) .collect(); ast::ItemKind::Trait(u, a, b, methods) } @@ -91,7 +109,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } ast::ItemKind::Enum(def, generics) => { let variants = def.variants.into_iter().filter_map(|v| { - if !(self.in_cfg)(&v.node.attrs) { + if !self.in_cfg(&v.node.attrs) { None } else { Some(Spanned { @@ -123,15 +141,12 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> // // NB: This is intentionally not part of the fold_expr() function // in order for fold_opt_expr() to be able to avoid this check - if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { - self.diagnostic.span_err(attr.span, - "removing an expression is not supported in this position"); - } + self.visit_unconfigurable_expr(&expr); fold_expr(self, expr) } fn fold_opt_expr(&mut self, expr: P) -> Option> { - if (self.in_cfg)(expr.attrs()) { + if self.in_cfg(expr.attrs()) { Some(fold_expr(self, expr)) } else { None @@ -139,7 +154,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { - if (self.in_cfg)(stmt.node.attrs()) { + if self.in_cfg(stmt.node.attrs()) { fold::noop_fold_stmt(stmt, self) } else { SmallVector::zero() @@ -151,7 +166,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } fn fold_item(&mut self, item: P) -> SmallVector> { - if (self.in_cfg)(&item.attrs) { + if self.in_cfg(&item.attrs) { SmallVector::one(item.map(|i| self.fold_item_simple(i))) } else { SmallVector::zero() @@ -170,23 +185,21 @@ pub fn strip_items<'a, F>(diagnostic: &'a Handler, ctxt.fold_crate(krate) } -fn fold_expr(cx: &mut Context, expr: P) -> P where - F: FnMut(&[ast::Attribute]) -> bool -{ +fn fold_expr(folder: &mut F, expr: P) -> P { expr.map(|ast::Expr {id, span, node, attrs}| { fold::noop_fold_expr(ast::Expr { id: id, node: match node { ast::ExprKind::Match(m, arms) => { ast::ExprKind::Match(m, arms.into_iter() - .filter(|a| (cx.in_cfg)(&a.attrs)) + .filter(|a| folder.in_cfg(&a.attrs)) .collect()) } _ => node }, span: span, attrs: attrs, - }, cx) + }, folder) }) } From 3d94823b4cb7eb760ddfd695da53a940d58445b1 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 16 May 2016 02:42:24 +0000 Subject: [PATCH 169/179] Refactor `CfgFolder::in_cfg` -> `CfgFolder::configure` --- src/libsyntax/config.rs | 74 ++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 54f3feee96ca..a22e08d42757 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use attr::AttrMetaMethods; +use attr::{AttrMetaMethods, HasAttrs}; use errors::Handler; use feature_gate::GatedCfgAttr; use fold::Folder; @@ -20,7 +20,7 @@ use ptr::P; use util::small_vector::SmallVector; pub trait CfgFolder: fold::Folder { - fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool; + fn configure(&mut self, node: T) -> Option; fn visit_unconfigurable_expr(&mut self, _expr: &ast::Expr) {} } @@ -32,8 +32,12 @@ struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { } impl<'a, F: FnMut(&[ast::Attribute]) -> bool> CfgFolder for Context<'a, F> { - fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { - (self.in_cfg)(attrs) + fn configure(&mut self, node: T) -> Option { + if (self.in_cfg)(node.attrs()) { + Some(node) + } else { + None + } } fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) { @@ -70,49 +74,39 @@ impl fold::Folder for T { fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, - items: foreign_mod.items.into_iter().filter(|item| { - self.in_cfg(&item.attrs) - }).collect(), + items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(), } } fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { let fold_struct = |this: &mut Self, vdata| match vdata { ast::VariantData::Struct(fields, id) => { - ast::VariantData::Struct(fields.into_iter().filter(|m| { - this.in_cfg(&m.attrs) - }).collect(), id) + let fields = fields.into_iter().filter_map(|field| this.configure(field)); + ast::VariantData::Struct(fields.collect(), id) } ast::VariantData::Tuple(fields, id) => { - ast::VariantData::Tuple(fields.into_iter().filter(|m| { - this.in_cfg(&m.attrs) - }).collect(), id) + let fields = fields.into_iter().filter_map(|field| this.configure(field)); + ast::VariantData::Tuple(fields.collect(), id) } ast::VariantData::Unit(id) => ast::VariantData::Unit(id) }; let item = match item { - ast::ItemKind::Impl(u, o, a, b, c, impl_items) => { - let impl_items = impl_items.into_iter() - .filter(|ii| self.in_cfg(&ii.attrs)) - .collect(); - ast::ItemKind::Impl(u, o, a, b, c, impl_items) + ast::ItemKind::Impl(u, o, a, b, c, items) => { + let items = items.into_iter().filter_map(|item| self.configure(item)).collect(); + ast::ItemKind::Impl(u, o, a, b, c, items) } - ast::ItemKind::Trait(u, a, b, methods) => { - let methods = methods.into_iter() - .filter(|ti| self.in_cfg(&ti.attrs)) - .collect(); - ast::ItemKind::Trait(u, a, b, methods) + ast::ItemKind::Trait(u, a, b, items) => { + let items = items.into_iter().filter_map(|item| self.configure(item)).collect(); + ast::ItemKind::Trait(u, a, b, items) } ast::ItemKind::Struct(def, generics) => { ast::ItemKind::Struct(fold_struct(self, def), generics) } ast::ItemKind::Enum(def, generics) => { let variants = def.variants.into_iter().filter_map(|v| { - if !self.in_cfg(&v.node.attrs) { - None - } else { - Some(Spanned { + self.configure(v).map(|v| { + Spanned { node: ast::Variant_ { name: v.node.name, attrs: v.node.attrs, @@ -120,8 +114,8 @@ impl fold::Folder for T { disr_expr: v.node.disr_expr, }, span: v.span - }) - } + } + }) }); ast::ItemKind::Enum(ast::EnumDef { variants: variants.collect(), @@ -146,19 +140,12 @@ impl fold::Folder for T { } fn fold_opt_expr(&mut self, expr: P) -> Option> { - if self.in_cfg(expr.attrs()) { - Some(fold_expr(self, expr)) - } else { - None - } + self.configure(expr).map(|expr| fold_expr(self, expr)) } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { - if self.in_cfg(stmt.node.attrs()) { - fold::noop_fold_stmt(stmt, self) - } else { - SmallVector::zero() - } + self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self)) + .unwrap_or(SmallVector::zero()) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { @@ -166,11 +153,8 @@ impl fold::Folder for T { } fn fold_item(&mut self, item: P) -> SmallVector> { - if self.in_cfg(&item.attrs) { - SmallVector::one(item.map(|i| self.fold_item_simple(i))) - } else { - SmallVector::zero() - } + self.configure(item).map(|item| SmallVector::one(item.map(|i| self.fold_item_simple(i)))) + .unwrap_or(SmallVector::zero()) } } @@ -192,7 +176,7 @@ fn fold_expr(folder: &mut F, expr: P) -> P { node: match node { ast::ExprKind::Match(m, arms) => { ast::ExprKind::Match(m, arms.into_iter() - .filter(|a| folder.in_cfg(&a.attrs)) + .filter_map(|a| folder.configure(a)) .collect()) } _ => node From fab7d375972f0cbc72aa7608db8ff9e22a078074 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 15 May 2016 09:22:58 +0000 Subject: [PATCH 170/179] Implement `CfgFolder` directly instead of passing a closure to `strip_items` --- src/libsyntax/config.rs | 41 ++++++++++++++--------------------------- src/libsyntax/test.rs | 22 +++++++++++++++------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a22e08d42757..1948c3afdbd0 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -26,14 +26,14 @@ pub trait CfgFolder: fold::Folder { /// A folder that strips out items that do not belong in the current /// configuration. -struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { - in_cfg: F, - diagnostic: &'a Handler, +pub struct StripUnconfigured<'a> { + diag: CfgDiagReal<'a, 'a>, + config: &'a ast::CrateConfig, } -impl<'a, F: FnMut(&[ast::Attribute]) -> bool> CfgFolder for Context<'a, F> { +impl<'a> CfgFolder for StripUnconfigured<'a> { fn configure(&mut self, node: T) -> Option { - if (self.in_cfg)(node.attrs()) { + if in_cfg(self.config, node.attrs(), &mut self.diag) { Some(node) } else { None @@ -43,7 +43,7 @@ impl<'a, F: FnMut(&[ast::Attribute]) -> bool> CfgFolder for Context<'a, F> { fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) { if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { let msg = "removing an expression is not supported in this position"; - self.diagnostic.span_err(attr.span, msg); + self.diag.diag.span_err(attr.span, msg); } } } @@ -58,16 +58,14 @@ pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, check_for_gated_stmt_expr_attributes(&krate, feature_gated_cfgs); let krate = process_cfg_attr(diagnostic, krate, feature_gated_cfgs); - let config = krate.config.clone(); - strip_items(diagnostic, - krate, - |attrs| { - let mut diag = CfgDiagReal { - diag: diagnostic, - feature_gated_cfgs: feature_gated_cfgs, - }; - in_cfg(&config, attrs, &mut diag) - }) + + StripUnconfigured { + config: &krate.config.clone(), + diag: CfgDiagReal { + diag: diagnostic, + feature_gated_cfgs: feature_gated_cfgs, + }, + }.fold_crate(krate) } impl fold::Folder for T { @@ -158,17 +156,6 @@ impl fold::Folder for T { } } -pub fn strip_items<'a, F>(diagnostic: &'a Handler, - krate: ast::Crate, in_cfg: F) -> ast::Crate where - F: FnMut(&[ast::Attribute]) -> bool, -{ - let mut ctxt = Context { - in_cfg: in_cfg, - diagnostic: diagnostic, - }; - ctxt.fold_crate(krate) -} - fn fold_expr(folder: &mut F, expr: P) -> P { expr.map(|ast::Expr {id, span, node, attrs}| { fold::noop_fold_expr(ast::Expr { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6785a8690d47..391c6aac8206 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -81,7 +81,7 @@ pub fn modify_for_testing(sess: &ParseSess, if should_test { generate_test_harness(sess, reexport_test_harness_main, krate, span_diagnostic) } else { - strip_test_functions(span_diagnostic, krate) + strip_test_functions(krate) } } @@ -304,14 +304,22 @@ fn generate_test_harness(sess: &ParseSess, return res; } -fn strip_test_functions(diagnostic: &errors::Handler, krate: ast::Crate) - -> ast::Crate { +fn strip_test_functions(krate: ast::Crate) -> ast::Crate { // When not compiling with --test we should not compile the // #[test] functions - config::strip_items(diagnostic, krate, |attrs| { - !attr::contains_name(&attrs[..], "test") && - !attr::contains_name(&attrs[..], "bench") - }) + struct StripTests; + impl config::CfgFolder for StripTests { + fn configure(&mut self, node: T) -> Option { + let strip_node = { + let attrs = node.attrs(); + attr::contains_name(attrs, "test") || attr::contains_name(attrs, "bench") + }; + + if strip_node { None } else { Some(node) } + } + } + + StripTests.fold_crate(krate) } /// Craft a span that will be ignored by the stability lint's From ae66cef0217563bcaf3dded172a76176b730b1d7 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 16 May 2016 04:42:57 +0000 Subject: [PATCH 171/179] Move cfg_attr processing and stmt/expr attribute gated feature checking into `StripUnconfigured` --- src/libsyntax/config.rs | 334 +++++++++++----------------------------- 1 file changed, 86 insertions(+), 248 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 1948c3afdbd0..62c922a4dbfd 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -13,7 +13,6 @@ use errors::Handler; use feature_gate::GatedCfgAttr; use fold::Folder; use {ast, fold, attr}; -use visit; use codemap::{Spanned, respan}; use ptr::P; @@ -21,6 +20,7 @@ use util::small_vector::SmallVector; pub trait CfgFolder: fold::Folder { fn configure(&mut self, node: T) -> Option; + fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {} fn visit_unconfigurable_expr(&mut self, _expr: &ast::Expr) {} } @@ -31,14 +31,78 @@ pub struct StripUnconfigured<'a> { config: &'a ast::CrateConfig, } -impl<'a> CfgFolder for StripUnconfigured<'a> { - fn configure(&mut self, node: T) -> Option { - if in_cfg(self.config, node.attrs(), &mut self.diag) { - Some(node) +impl<'a> StripUnconfigured<'a> { + // Determine if an item should be translated in the current crate + // configuration based on the item's attributes + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { + attrs.iter().all(|attr| { + let mis = match attr.node.value.node { + ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis, + _ => return true + }; + + if mis.len() != 1 { + self.diag.emit_error(|diagnostic| { + diagnostic.span_err(attr.span, "expected 1 cfg-pattern"); + }); + return true; + } + + attr::cfg_matches(self.config, &mis[0], &mut self.diag) + }) + } + + fn process_cfg_attrs(&mut self, attrs: Vec) -> Vec { + attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() + } + + fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option { + if !attr.check_name("cfg_attr") { + return Some(attr); + } + + let attr_list = match attr.meta_item_list() { + Some(attr_list) => attr_list, + None => { + let msg = "expected `#[cfg_attr(, )]`"; + self.diag.diag.span_err(attr.span, msg); + return None; + } + }; + let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) { + (2, Some(cfg), Some(mi)) => (cfg, mi), + _ => { + let msg = "expected `#[cfg_attr(, )]`"; + self.diag.diag.span_err(attr.span, msg); + return None; + } + }; + + if attr::cfg_matches(self.config, &cfg, &mut self.diag) { + Some(respan(mi.span, ast::Attribute_ { + id: attr::mk_attr_id(), + style: attr.node.style, + value: mi.clone(), + is_sugared_doc: false, + })) } else { None } } +} + +impl<'a> CfgFolder for StripUnconfigured<'a> { + fn configure(&mut self, node: T) -> Option { + let node = node.map_attrs(|attrs| self.process_cfg_attrs(attrs)); + if self.in_cfg(node.attrs()) { Some(node) } else { None } + } + + fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) { + // flag the offending attributes + for attr in attrs.iter() { + self.diag.feature_gated_cfgs.push(GatedCfgAttr::GatedAttr(attr.span)); + } + } fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) { if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { @@ -54,11 +118,6 @@ pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, feature_gated_cfgs: &mut Vec) -> ast::Crate { - // Need to do this check here because cfg runs before feature_gates - check_for_gated_stmt_expr_attributes(&krate, feature_gated_cfgs); - - let krate = process_cfg_attr(diagnostic, krate, feature_gated_cfgs); - StripUnconfigured { config: &krate.config.clone(), diag: CfgDiagReal { @@ -72,7 +131,9 @@ impl fold::Folder for T { fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, - items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(), + items: foreign_mod.items.into_iter().filter_map(|item| { + self.configure(item).map(|item| fold::noop_fold_foreign_item(item, self)) + }).collect(), } } @@ -126,6 +187,7 @@ impl fold::Folder for T { } fn fold_expr(&mut self, expr: P) -> P { + self.visit_stmt_or_expr_attrs(expr.attrs()); // If an expr is valid to cfg away it will have been removed by the // outer stmt or expression folder before descending in here. // Anything else is always required, and thus has to error out @@ -142,6 +204,19 @@ impl fold::Folder for T { } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + let is_item = match stmt.node { + ast::StmtKind::Decl(ref decl, _) => match decl.node { + ast::DeclKind::Item(_) => true, + _ => false, + }, + _ => false, + }; + + // avoid calling `visit_stmt_or_expr_attrs` on items + if !is_item { + self.visit_stmt_or_expr_attrs(stmt.attrs()); + } + self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self)) .unwrap_or(SmallVector::zero()) } @@ -178,205 +253,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool { attr.check_name("cfg") } -// Determine if an item should be translated in the current crate -// configuration based on the item's attributes -fn in_cfg(cfg: &[P], - attrs: &[ast::Attribute], - diag: &mut T) -> bool { - attrs.iter().all(|attr| { - let mis = match attr.node.value.node { - ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis, - _ => return true - }; - - if mis.len() != 1 { - diag.emit_error(|diagnostic| { - diagnostic.span_err(attr.span, "expected 1 cfg-pattern"); - }); - return true; - } - - attr::cfg_matches(cfg, &mis[0], diag) - }) -} - -struct CfgAttrFolder<'a, T> { - diag: T, - config: &'a ast::CrateConfig, -} - -// Process `#[cfg_attr]`. -fn process_cfg_attr(diagnostic: &Handler, krate: ast::Crate, - feature_gated_cfgs: &mut Vec) -> ast::Crate { - let mut fld = CfgAttrFolder { - diag: CfgDiagReal { - diag: diagnostic, - feature_gated_cfgs: feature_gated_cfgs, - }, - config: &krate.config.clone(), - }; - fld.fold_crate(krate) -} - -impl<'a, T: CfgDiag> fold::Folder for CfgAttrFolder<'a, T> { - fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { - if !attr.check_name("cfg_attr") { - return fold::noop_fold_attribute(attr, self); - } - - let attr_list = match attr.meta_item_list() { - Some(attr_list) => attr_list, - None => { - self.diag.emit_error(|diag| { - diag.span_err(attr.span, - "expected `#[cfg_attr(, )]`"); - }); - return None; - } - }; - let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) { - (2, Some(cfg), Some(mi)) => (cfg, mi), - _ => { - self.diag.emit_error(|diag| { - diag.span_err(attr.span, - "expected `#[cfg_attr(, )]`"); - }); - return None; - } - }; - - if attr::cfg_matches(&self.config[..], &cfg, &mut self.diag) { - Some(respan(mi.span, ast::Attribute_ { - id: attr::mk_attr_id(), - style: attr.node.style, - value: mi.clone(), - is_sugared_doc: false, - })) - } else { - None - } - } - - // Need the ability to run pre-expansion. - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } -} - -fn check_for_gated_stmt_expr_attributes(krate: &ast::Crate, - discovered: &mut Vec) { - let mut v = StmtExprAttrFeatureVisitor { - config: &krate.config, - discovered: discovered, - }; - visit::walk_crate(&mut v, krate); -} - -/// To cover this feature, we need to discover all attributes -/// so we need to run before cfg. -struct StmtExprAttrFeatureVisitor<'a, 'b> { - config: &'a ast::CrateConfig, - discovered: &'b mut Vec, -} - -// Runs the cfg_attr and cfg folders locally in "silent" mode -// to discover attribute use on stmts or expressions ahead of time -impl<'v, 'a, 'b> visit::Visitor<'v> for StmtExprAttrFeatureVisitor<'a, 'b> { - fn visit_stmt(&mut self, s: &'v ast::Stmt) { - // check if there even are any attributes on this node - let stmt_attrs = s.node.attrs(); - if stmt_attrs.len() > 0 { - // attributes on items are fine - if let ast::StmtKind::Decl(ref decl, _) = s.node { - if let ast::DeclKind::Item(_) = decl.node { - visit::walk_stmt(self, s); - return; - } - } - - // flag the offending attributes - for attr in stmt_attrs { - self.discovered.push(GatedCfgAttr::GatedAttr(attr.span)); - } - - // if the node does not end up being cfg-d away, walk down - if node_survives_cfg(stmt_attrs, self.config) { - visit::walk_stmt(self, s); - } - } else { - visit::walk_stmt(self, s); - } - } - - fn visit_expr(&mut self, ex: &'v ast::Expr) { - // check if there even are any attributes on this node - let expr_attrs = ex.attrs(); - if expr_attrs.len() > 0 { - - // flag the offending attributes - for attr in expr_attrs { - self.discovered.push(GatedCfgAttr::GatedAttr(attr.span)); - } - - // if the node does not end up being cfg-d away, walk down - if node_survives_cfg(expr_attrs, self.config) { - visit::walk_expr(self, ex); - } - } else { - visit::walk_expr(self, ex); - } - } - - fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) { - if node_survives_cfg(&i.attrs, self.config) { - visit::walk_foreign_item(self, i); - } - } - - fn visit_item(&mut self, i: &'v ast::Item) { - if node_survives_cfg(&i.attrs, self.config) { - visit::walk_item(self, i); - } - } - - fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) { - if node_survives_cfg(&ii.attrs, self.config) { - visit::walk_impl_item(self, ii); - } - } - - fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) { - if node_survives_cfg(&ti.attrs, self.config) { - visit::walk_trait_item(self, ti); - } - } - - fn visit_struct_field(&mut self, s: &'v ast::StructField) { - if node_survives_cfg(&s.attrs, self.config) { - visit::walk_struct_field(self, s); - } - } - - fn visit_variant(&mut self, v: &'v ast::Variant, - g: &'v ast::Generics, item_id: ast::NodeId) { - if node_survives_cfg(&v.node.attrs, self.config) { - visit::walk_variant(self, v, g, item_id); - } - } - - fn visit_arm(&mut self, a: &'v ast::Arm) { - if node_survives_cfg(&a.attrs, self.config) { - visit::walk_arm(self, a); - } - } - - // This visitor runs pre expansion, so we need to prevent - // the default panic here - fn visit_mac(&mut self, mac: &'v ast::Mac) { - visit::walk_mac(self, mac) - } -} - pub trait CfgDiag { fn emit_error(&mut self, f: F) where F: FnMut(&Handler); fn flag_gated(&mut self, f: F) where F: FnMut(&mut Vec); @@ -395,41 +271,3 @@ impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> { f(self.feature_gated_cfgs) } } - -struct CfgDiagSilent { - error: bool, -} - -impl CfgDiag for CfgDiagSilent { - fn emit_error(&mut self, _: F) where F: FnMut(&Handler) { - self.error = true; - } - fn flag_gated(&mut self, _: F) where F: FnMut(&mut Vec) {} -} - -fn node_survives_cfg(attrs: &[ast::Attribute], - config: &ast::CrateConfig) -> bool { - let mut survives_cfg = true; - - for attr in attrs { - let mut fld = CfgAttrFolder { - diag: CfgDiagSilent { error: false }, - config: config, - }; - let attr = fld.fold_attribute(attr.clone()); - - // In case of error we can just return true, - // since the actual cfg folders will end compilation anyway. - - if fld.diag.error { return true; } - - survives_cfg &= attr.map(|attr| { - let mut diag = CfgDiagSilent { error: false }; - let r = in_cfg(config, &[attr], &mut diag); - if diag.error { return true; } - r - }).unwrap_or(true) - } - - survives_cfg -} From a90206ca92561cf8f267af5fc9f878ef99f6b4aa Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 26 May 2016 23:56:25 +0000 Subject: [PATCH 172/179] Process `cfg_attr` attributes on non-optional expressions --- src/libsyntax/config.rs | 66 ++++++++++++++++++++++------------------- src/libsyntax/test.rs | 9 ++---- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 62c922a4dbfd..e1c17ca43d3a 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -19,9 +19,15 @@ use ptr::P; use util::small_vector::SmallVector; pub trait CfgFolder: fold::Folder { - fn configure(&mut self, node: T) -> Option; + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool; + fn process_attrs(&mut self, node: T) -> T { node } fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {} - fn visit_unconfigurable_expr(&mut self, _expr: &ast::Expr) {} + fn visit_unremovable_expr(&mut self, _expr: &ast::Expr) {} + + fn configure(&mut self, node: T) -> Option { + let node = self.process_attrs(node); + if self.in_cfg(node.attrs()) { Some(node) } else { None } + } } /// A folder that strips out items that do not belong in the current @@ -32,30 +38,6 @@ pub struct StripUnconfigured<'a> { } impl<'a> StripUnconfigured<'a> { - // Determine if an item should be translated in the current crate - // configuration based on the item's attributes - fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { - attrs.iter().all(|attr| { - let mis = match attr.node.value.node { - ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis, - _ => return true - }; - - if mis.len() != 1 { - self.diag.emit_error(|diagnostic| { - diagnostic.span_err(attr.span, "expected 1 cfg-pattern"); - }); - return true; - } - - attr::cfg_matches(self.config, &mis[0], &mut self.diag) - }) - } - - fn process_cfg_attrs(&mut self, attrs: Vec) -> Vec { - attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() - } - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option { if !attr.check_name("cfg_attr") { return Some(attr); @@ -92,9 +74,30 @@ impl<'a> StripUnconfigured<'a> { } impl<'a> CfgFolder for StripUnconfigured<'a> { - fn configure(&mut self, node: T) -> Option { - let node = node.map_attrs(|attrs| self.process_cfg_attrs(attrs)); - if self.in_cfg(node.attrs()) { Some(node) } else { None } + // Determine if an item should be translated in the current crate + // configuration based on the item's attributes + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { + attrs.iter().all(|attr| { + let mis = match attr.node.value.node { + ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis, + _ => return true + }; + + if mis.len() != 1 { + self.diag.emit_error(|diagnostic| { + diagnostic.span_err(attr.span, "expected 1 cfg-pattern"); + }); + return true; + } + + attr::cfg_matches(self.config, &mis[0], &mut self.diag) + }) + } + + fn process_attrs(&mut self, node: T) -> T { + node.map_attrs(|attrs| { + attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() + }) } fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) { @@ -104,7 +107,7 @@ impl<'a> CfgFolder for StripUnconfigured<'a> { } } - fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) { + fn visit_unremovable_expr(&mut self, expr: &ast::Expr) { if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { let msg = "removing an expression is not supported in this position"; self.diag.diag.span_err(attr.span, msg); @@ -195,7 +198,8 @@ impl fold::Folder for T { // // NB: This is intentionally not part of the fold_expr() function // in order for fold_opt_expr() to be able to avoid this check - self.visit_unconfigurable_expr(&expr); + self.visit_unremovable_expr(&expr); + let expr = self.process_attrs(expr); fold_expr(self, expr) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 391c6aac8206..6fbbed2ee984 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -309,13 +309,8 @@ fn strip_test_functions(krate: ast::Crate) -> ast::Crate { // #[test] functions struct StripTests; impl config::CfgFolder for StripTests { - fn configure(&mut self, node: T) -> Option { - let strip_node = { - let attrs = node.attrs(); - attr::contains_name(attrs, "test") || attr::contains_name(attrs, "bench") - }; - - if strip_node { None } else { Some(node) } + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { + !attr::contains_name(attrs, "test") && !attr::contains_name(attrs, "bench") } } From a9bb0744ee01682ce16f3c94320fec1603cd4a38 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 18 May 2016 01:50:29 +0000 Subject: [PATCH 173/179] Test that a feature gated cfg variable in a `cfg_attr` on an unconfigured item is allowed --- src/test/compile-fail/expanded-cfg.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/expanded-cfg.rs b/src/test/compile-fail/expanded-cfg.rs index 2f74aeba9eb4..a15e0548a868 100644 --- a/src/test/compile-fail/expanded-cfg.rs +++ b/src/test/compile-fail/expanded-cfg.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] +#![feature(custom_attribute, rustc_attrs)] macro_rules! mac { {} => { @@ -16,6 +16,9 @@ macro_rules! mac { mod m { #[lang_item] fn f() {} + + #[cfg_attr(target_thread_local, custom)] + fn g() {} } } } From 8f6938f506d3d04bf1b97e5475e881096333ca24 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 17 May 2016 21:20:09 +0000 Subject: [PATCH 174/179] Update spans' `expn_id` during the marking fold --- src/libsyntax/codemap.rs | 25 ------------ src/libsyntax/ext/expand.rs | 76 ++++++++++--------------------------- 2 files changed, 20 insertions(+), 81 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3b13bf2fc50b..d391cd0be7b1 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1258,31 +1258,6 @@ impl CodeMap { return a; } - /// Check if the backtrace `subtrace` contains `suptrace` as a prefix. - pub fn more_specific_trace(&self, - mut subtrace: ExpnId, - suptrace: ExpnId) - -> bool { - loop { - if subtrace == suptrace { - return true; - } - - let stop = self.with_expn_info(subtrace, |opt_expn_info| { - if let Some(expn_info) = opt_expn_info { - subtrace = expn_info.call_site.expn_id; - false - } else { - true - } - }); - - if stop { - return false; - } - } - } - pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId { let mut expansions = self.expansions.borrow_mut(); expansions.push(expn_info); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ecca370fb8a3..fd462ddddd23 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -18,7 +18,7 @@ use ext::build::AstBuilder; use attr; use attr::{AttrMetaMethods, WithAttrs, ThinAttributesExt}; use codemap; -use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; +use codemap::{Span, Spanned, ExpnInfo, ExpnId, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; use feature_gate::{self, Features}; use fold; @@ -33,7 +33,6 @@ use visit::Visitor; use std_inject; use std::collections::HashSet; -use std::env; // A trait for AST nodes and AST node lists into which macro invocations may expand. trait MacroGenerable: Sized { @@ -160,10 +159,10 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let new_node = ast::ExprKind::Closure(capture_clause, rewritten_fn_decl, rewritten_block, - fld.new_span(fn_decl_span)); + fn_decl_span); P(ast::Expr{ id:id, node: new_node, - span: fld.new_span(span), + span: span, attrs: fold_thin_attrs(attrs, fld) }) } @@ -322,7 +321,7 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec Folder for PatIdentRenamer<'a> { mtwt::apply_renames(self.renames, ident.ctxt)); let new_node = PatKind::Ident(binding_mode, - Spanned{span: self.new_span(sp), node: new_ident}, + Spanned{span: sp, node: new_ident}, sub.map(|p| self.fold_pat(p))); ast::Pat { id: id, node: new_node, - span: self.new_span(span) + span: span, } }, _ => unreachable!() @@ -774,7 +773,7 @@ fn expand_annotatable(a: Annotatable, } _ => unreachable!() }, - span: fld.new_span(ti.span) + span: ti.span, }) } _ => fold::noop_fold_trait_item(it.unwrap(), fld) @@ -914,7 +913,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) } _ => unreachable!() }, - span: fld.new_span(ii.span) + span: ii.span, }), ast::ImplItemKind::Macro(mac) => { expand_mac_invoc(mac, None, ii.attrs, ii.span, fld) @@ -1059,10 +1058,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { fn fold_ty(&mut self, ty: P) -> P { expand_type(ty, self) } - - fn new_span(&mut self, span: Span) -> Span { - new_span(self.cx, span) - } } impl<'a, 'b> MacroExpander<'a, 'b> { @@ -1080,45 +1075,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } -fn new_span(cx: &ExtCtxt, sp: Span) -> Span { - debug!("new_span(sp={:?})", sp); - - if cx.codemap().more_specific_trace(sp.expn_id, cx.backtrace()) { - // If the span we are looking at has a backtrace that has more - // detail than our current backtrace, then we keep that - // backtrace. Honestly, I have no idea if this makes sense, - // because I have no idea why we are stripping the backtrace - // below. But the reason I made this change is because, in - // deriving, we were generating attributes with a specific - // backtrace, which was essential for `#[structural_match]` to - // be properly supported, but these backtraces were being - // stripped and replaced with a null backtrace. Sort of - // unclear why this is the case. --nmatsakis - debug!("new_span: keeping trace from {:?} because it is more specific", - sp.expn_id); - sp - } else { - // This discards information in the case of macro-defining macros. - // - // The comment above was originally added in - // b7ec2488ff2f29681fe28691d20fd2c260a9e454 in Feb 2012. I - // *THINK* the reason we are doing this is because we want to - // replace the backtrace of the macro contents with the - // backtrace that contains the macro use. But it's pretty - // unclear to me. --nmatsakis - let sp1 = Span { - lo: sp.lo, - hi: sp.hi, - expn_id: cx.backtrace(), - }; - debug!("new_span({:?}) = {:?}", sp, sp1); - if sp.expn_id.into_u32() == 0 && env::var_os("NDM").is_some() { - panic!("NDM"); - } - sp1 - } -} - pub struct ExpansionConfig<'feat> { pub crate_name: String, pub features: Option<&'feat Features>, @@ -1205,8 +1161,9 @@ pub fn expand_crate(mut cx: ExtCtxt, // the ones defined here include: // Marker - add a mark to a context -// A Marker adds the given mark to the syntax context -struct Marker { mark: Mrk } +// A Marker adds the given mark to the syntax context and +// sets spans' `expn_id` to the given expn_id (unless it is `None`). +struct Marker { mark: Mrk, expn_id: Option } impl Folder for Marker { fn fold_ident(&mut self, id: Ident) -> Ident { @@ -1219,14 +1176,21 @@ impl Folder for Marker { tts: self.fold_tts(&node.tts), ctxt: mtwt::apply_mark(self.mark, node.ctxt), }, - span: span, + span: self.new_span(span), + } + } + + fn new_span(&mut self, mut span: Span) -> Span { + if let Some(expn_id) = self.expn_id { + span.expn_id = expn_id; } + span } } // apply a given mark to the given token trees. Used prior to expansion of a macro. fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec { - noop_fold_tts(tts, &mut Marker{mark:m}) + noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) } /// Check that there are no macro invocations left in the AST: From 174dfaca43fffca02b95613563a9e8f3dda141e6 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 16 May 2016 10:09:23 +0000 Subject: [PATCH 175/179] Strip unconfigured items during macro expansion --- src/librustc_driver/driver.rs | 9 --------- src/libsyntax/config.rs | 19 ++++++++++++------- src/libsyntax/ext/expand.rs | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 34527d1689c0..a8ddc7e7bdab 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -720,16 +720,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, ret }); - // JBC: make CFG processing part of expansion to avoid this problem: - - // strip again, in case expansion added anything with a #[cfg]. krate = sess.track_errors(|| { - let krate = time(time_passes, "configuration 2", || { - syntax::config::strip_unconfigured_items(sess.diagnostic(), - krate, - &mut feature_gated_cfgs) - }); - time(time_passes, "gated configuration checking", || { let features = sess.features.borrow(); feature_gated_cfgs.sort(); diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index e1c17ca43d3a..77f20934d805 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -38,6 +38,16 @@ pub struct StripUnconfigured<'a> { } impl<'a> StripUnconfigured<'a> { + pub fn new(config: &'a ast::CrateConfig, + diagnostic: &'a Handler, + feature_gated_cfgs: &'a mut Vec) + -> Self { + StripUnconfigured { + config: config, + diag: CfgDiagReal { diag: diagnostic, feature_gated_cfgs: feature_gated_cfgs }, + } + } + fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option { if !attr.check_name("cfg_attr") { return Some(attr); @@ -121,13 +131,8 @@ pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, feature_gated_cfgs: &mut Vec) -> ast::Crate { - StripUnconfigured { - config: &krate.config.clone(), - diag: CfgDiagReal { - diag: diagnostic, - feature_gated_cfgs: feature_gated_cfgs, - }, - }.fold_crate(krate) + let config = &krate.config.clone(); + StripUnconfigured::new(config, diagnostic, feature_gated_cfgs).fold_crate(krate) } impl fold::Folder for T { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fd462ddddd23..17b56c574bc9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -19,6 +19,7 @@ use attr; use attr::{AttrMetaMethods, WithAttrs, ThinAttributesExt}; use codemap; use codemap::{Span, Spanned, ExpnInfo, ExpnId, NameAndSpan, MacroBang, MacroAttribute}; +use config::StripUnconfigured; use ext::base::*; use feature_gate::{self, Features}; use fold; @@ -76,6 +77,17 @@ impl_macro_generable! { "statement", .make_stmts, lift .fold_stmt, |_span| SmallVector::zero(); } +impl MacroGenerable for Option> { + fn kind_name() -> &'static str { "expression" } + fn dummy(_span: Span) -> Self { None } + fn make_with<'a>(result: Box) -> Option { + result.make_expr().map(Some) + } + fn fold_with(self, folder: &mut F) -> Self { + self.and_then(|expr| folder.fold_opt_expr(expr)) + } +} + pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { return e.and_then(|ast::Expr {id, node, span, attrs}| match node { @@ -322,7 +334,8 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> { MacroExpander { cx: cx } } + + fn strip_unconfigured(&mut self) -> StripUnconfigured { + StripUnconfigured::new(&self.cx.cfg, + &self.cx.parse_sess.span_diagnostic, + self.cx.feature_gated_cfgs) + } } impl<'a, 'b> Folder for MacroExpander<'a, 'b> { @@ -998,6 +1017,19 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { expand_expr(expr, self) } + fn fold_opt_expr(&mut self, expr: P) -> Option> { + match expr.node { + ast::ExprKind::Mac(_) => {} + _ => return Some(expand_expr(expr, self)), + } + + expr.and_then(|ast::Expr {node, span, attrs, ..}| match node { + ast::ExprKind::Mac(mac) => + expand_mac_invoc(mac, None, attrs.into_attr_vec(), span, self), + _ => unreachable!(), + }) + } + fn fold_pat(&mut self, pat: P) -> P { expand_pat(pat, self) } From e415fe97a6db1e8ac6d00f2e2a5f2cfdb46c741a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 26 May 2016 23:48:45 +0000 Subject: [PATCH 176/179] Refactor `expand_expr` --- src/libsyntax/ext/expand.rs | 57 ++++++++++++++----------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 17b56c574bc9..c3202dbdbb49 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -88,25 +88,24 @@ impl MacroGenerable for Option> { } } -pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { - return e.and_then(|ast::Expr {id, node, span, attrs}| match node { - +pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P { + match expr.node { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprKind::Mac(mac) => { - expand_mac_invoc(mac, None, attrs.into_attr_vec(), span, fld) + expand_mac_invoc(mac, None, expr.attrs.into_attr_vec(), expr.span, fld) } ast::ExprKind::While(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); - fld.cx.expr(span, ast::ExprKind::While(cond, body, opt_ident)) - .with_attrs(fold_thin_attrs(attrs, fld)) + fld.cx.expr(expr.span, ast::ExprKind::While(cond, body, opt_ident)) + .with_attrs(fold_thin_attrs(expr.attrs, fld)) } - ast::ExprKind::WhileLet(pat, expr, body, opt_ident) => { + ast::ExprKind::WhileLet(pat, cond, body, opt_ident) => { let pat = fld.fold_pat(pat); - let expr = fld.fold_expr(expr); + let cond = fld.fold_expr(cond); // Hygienic renaming of the body. let ((body, opt_ident), mut rewritten_pats) = @@ -118,14 +117,14 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }); assert!(rewritten_pats.len() == 1); - let wl = ast::ExprKind::WhileLet(rewritten_pats.remove(0), expr, body, opt_ident); - fld.cx.expr(span, wl).with_attrs(fold_thin_attrs(attrs, fld)) + let wl = ast::ExprKind::WhileLet(rewritten_pats.remove(0), cond, body, opt_ident); + fld.cx.expr(expr.span, wl).with_attrs(fold_thin_attrs(expr.attrs, fld)) } ast::ExprKind::Loop(loop_block, opt_ident) => { let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); - fld.cx.expr(span, ast::ExprKind::Loop(loop_block, opt_ident)) - .with_attrs(fold_thin_attrs(attrs, fld)) + fld.cx.expr(expr.span, ast::ExprKind::Loop(loop_block, opt_ident)) + .with_attrs(fold_thin_attrs(expr.attrs, fld)) } ast::ExprKind::ForLoop(pat, head, body, opt_ident) => { @@ -143,7 +142,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let head = fld.fold_expr(head); let fl = ast::ExprKind::ForLoop(rewritten_pats.remove(0), head, body, opt_ident); - fld.cx.expr(span, fl).with_attrs(fold_thin_attrs(attrs, fld)) + fld.cx.expr(expr.span, fl).with_attrs(fold_thin_attrs(expr.attrs, fld)) } ast::ExprKind::IfLet(pat, sub_expr, body, else_opt) => { @@ -162,7 +161,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt)); let sub_expr = fld.fold_expr(sub_expr); let il = ast::ExprKind::IfLet(rewritten_pats.remove(0), sub_expr, body, else_opt); - fld.cx.expr(span, il).with_attrs(fold_thin_attrs(attrs, fld)) + fld.cx.expr(expr.span, il).with_attrs(fold_thin_attrs(expr.attrs, fld)) } ast::ExprKind::Closure(capture_clause, fn_decl, block, fn_decl_span) => { @@ -172,21 +171,14 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { rewritten_fn_decl, rewritten_block, fn_decl_span); - P(ast::Expr{ id:id, + P(ast::Expr{ id: expr.id, node: new_node, - span: span, - attrs: fold_thin_attrs(attrs, fld) }) + span: expr.span, + attrs: fold_thin_attrs(expr.attrs, fld) }) } - _ => { - P(noop_fold_expr(ast::Expr { - id: id, - node: node, - span: span, - attrs: attrs - }, fld)) - } - }); + _ => P(noop_fold_expr(expr, fld)), + } } /// Expand a macro invocation. Returns the result of expansion. @@ -1014,19 +1006,14 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { } fn fold_expr(&mut self, expr: P) -> P { - expand_expr(expr, self) + expr.and_then(|expr| expand_expr(expr, self)) } fn fold_opt_expr(&mut self, expr: P) -> Option> { - match expr.node { - ast::ExprKind::Mac(_) => {} - _ => return Some(expand_expr(expr, self)), - } - - expr.and_then(|ast::Expr {node, span, attrs, ..}| match node { + expr.and_then(|expr| match expr.node { ast::ExprKind::Mac(mac) => - expand_mac_invoc(mac, None, attrs.into_attr_vec(), span, self), - _ => unreachable!(), + expand_mac_invoc(mac, None, expr.attrs.into_attr_vec(), expr.span, self), + _ => Some(expand_expr(expr, self)), }) } From 82b0a57e3e0224517541841df6022701b7fe33e2 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Fri, 27 May 2016 08:06:17 +0530 Subject: [PATCH 177/179] rustfmt on liblog --- src/liblog/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index a71f6efe54eb..517cd016e8a3 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -179,7 +179,7 @@ use std::io::prelude::*; use std::mem; use std::env; use std::slice; -use std::sync::{Once, Mutex, ONCE_INIT}; +use std::sync::{Mutex, ONCE_INIT, Once}; use directive::LOG_LEVEL_NAMES; @@ -290,9 +290,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // frob the slot while we're doing the logging. This will destroy any logger // set during logging. let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); - let mut logger = logger.unwrap_or_else(|| { - Box::new(DefaultLogger { handle: io::stderr() }) - }); + let mut logger = logger.unwrap_or_else(|| Box::new(DefaultLogger { handle: io::stderr() })); logger.log(&LogRecord { level: LogLevel(level), args: args, From fa084aa4703e7e48fa845bed2b539a018d0bcb45 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 18 May 2016 02:02:04 +0000 Subject: [PATCH 178/179] Test that unconfigured macro-expanded macro invocations are not expanded. --- src/test/compile-fail/expanded-cfg.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/compile-fail/expanded-cfg.rs b/src/test/compile-fail/expanded-cfg.rs index a15e0548a868..77351f6e4f17 100644 --- a/src/test/compile-fail/expanded-cfg.rs +++ b/src/test/compile-fail/expanded-cfg.rs @@ -20,6 +20,9 @@ macro_rules! mac { #[cfg_attr(target_thread_local, custom)] fn g() {} } + + #[cfg(attr)] + unconfigured_invocation!(); } } From b08c570cc31dbd085378a337453eb6e2cfe3c462 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 24 May 2016 05:15:07 +0000 Subject: [PATCH 179/179] Comment methods in `CfgFolder` --- src/libsyntax/config.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 77f20934d805..14035d8d116a 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -19,9 +19,16 @@ use ptr::P; use util::small_vector::SmallVector; pub trait CfgFolder: fold::Folder { + // Check if a node with the given attributes is in this configuration. fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool; + + // Update a node before checking if it is in this configuration (used to implement `cfg_attr`). fn process_attrs(&mut self, node: T) -> T { node } + + // Visit attributes on expression and statements (but not attributes on items in blocks). fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {} + + // Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`. fn visit_unremovable_expr(&mut self, _expr: &ast::Expr) {} fn configure(&mut self, node: T) -> Option {