]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #27132 - apasel422:issue-23491, r=arielb1
authorbors <bors@rust-lang.org>
Mon, 20 Jul 2015 03:19:12 +0000 (03:19 +0000)
committerbors <bors@rust-lang.org>
Mon, 20 Jul 2015 03:19:12 +0000 (03:19 +0000)
closes #23491

src/libcore/fmt/num.rs
src/libcore/num/mod.rs
src/libcoretest/num/mod.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/lib.rs
src/libsyntax/parse/parser.rs
src/test/compile-fail/issue-15919.rs [new file with mode: 0644]
src/test/compile-fail/issue-27042.rs [new file with mode: 0644]
src/test/compile-fail/trait-impl-can-not-have-untraitful-items.rs [new file with mode: 0644]
src/test/compile-fail/trait-impl-can-not-have-untraitful-methods.rs [deleted file]

index fc49f87d107699c2defce051f06df1100f6c37ce..a098840c77a51a55cc3a26c458d84df260b8216d 100644 (file)
 use num::Zero;
 use ops::{Div, Rem, Sub};
 use str;
+use slice;
+use ptr;
+use mem;
 
 #[doc(hidden)]
 trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
            Sub<Output=Self> + Copy {
     fn from_u8(u: u8) -> Self;
     fn to_u8(&self) -> u8;
+    fn to_u32(&self) -> u32;
+    fn to_u64(&self) -> u64;
 }
 
 macro_rules! doit {
     ($($t:ident)*) => ($(impl Int for $t {
         fn from_u8(u: u8) -> $t { u as $t }
         fn to_u8(&self) -> u8 { *self as u8 }
+        fn to_u32(&self) -> u32 { *self as u32 }
+        fn to_u64(&self) -> u64 { *self as u64 }
     })*)
 }
 doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
@@ -188,6 +195,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         }
     }
 }
+
 macro_rules! int_base {
     ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -209,9 +217,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         }
     }
 }
+
 macro_rules! integer {
     ($Int:ident, $Uint:ident) => {
-        int_base! { Display  for $Int as $Int   -> Decimal }
         int_base! { Binary   for $Int as $Uint  -> Binary }
         int_base! { Octal    for $Int as $Uint  -> Octal }
         int_base! { LowerHex for $Int as $Uint  -> LowerHex }
@@ -219,7 +227,6 @@ macro_rules! integer {
         radix_fmt! { $Int as $Int, fmt_int }
         debug! { $Int }
 
-        int_base! { Display  for $Uint as $Uint -> Decimal }
         int_base! { Binary   for $Uint as $Uint -> Binary }
         int_base! { Octal    for $Uint as $Uint -> Octal }
         int_base! { LowerHex for $Uint as $Uint -> LowerHex }
@@ -233,3 +240,80 @@ macro_rules! integer {
 integer! { i16, u16 }
 integer! { i32, u32 }
 integer! { i64, u64 }
+
+const DEC_DIGITS_LUT: &'static[u8] =
+    b"0001020304050607080910111213141516171819\
+      2021222324252627282930313233343536373839\
+      4041424344454647484950515253545556575859\
+      6061626364656667686970717273747576777879\
+      8081828384858687888990919293949596979899";
+
+macro_rules! impl_Display {
+    ($($t:ident),*: $conv_fn:ident) => ($(
+    impl fmt::Display for $t {
+        #[allow(unused_comparisons)]
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            let is_positive = *self >= 0;
+            let mut n = if is_positive {
+                self.$conv_fn()
+            } else {
+                // convert the negative num to positive by summing 1 to it's 2 complement
+                (!self.$conv_fn()).wrapping_add(1)
+            };
+            let mut buf: [u8; 20] = unsafe { mem::uninitialized() };
+            let mut curr = buf.len() as isize;
+            let buf_ptr = buf.as_mut_ptr();
+            let lut_ptr = DEC_DIGITS_LUT.as_ptr();
+
+            unsafe {
+                // eagerly decode 4 characters at a time
+                if <$t>::max_value() as u64 >= 10000 {
+                    while n >= 10000 {
+                        let rem = (n % 10000) as isize;
+                        n /= 10000;
+
+                        let d1 = (rem / 100) << 1;
+                        let d2 = (rem % 100) << 1;
+                        curr -= 4;
+                        ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+                        ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
+                    }
+                }
+
+                // if we reach here numbers are <= 9999, so at most 4 chars long
+                let mut n = n as isize; // possibly reduce 64bit math
+
+                // decode 2 more chars, if > 2 chars
+                if n >= 100 {
+                    let d1 = (n % 100) << 1;
+                    n /= 100;
+                    curr -= 2;
+                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+                }
+
+                // decode last 1 or 2 chars
+                if n < 10 {
+                    curr -= 1;
+                    *buf_ptr.offset(curr) = (n as u8) + 48;
+                } else {
+                    let d1 = n << 1;
+                    curr -= 2;
+                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+                }
+            }
+
+            let buf_slice = unsafe {
+                str::from_utf8_unchecked(
+                    slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))
+            };
+            f.pad_integral(is_positive, "", buf_slice)
+        }
+    })*);
+}
+
+impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
+impl_Display!(i64, u64: to_u64);
+#[cfg(target_pointer_width = "32")]
+impl_Display!(isize, usize: to_u32);
+#[cfg(target_pointer_width = "64")]
+impl_Display!(isize, usize: to_u64);
index 6413cc36d269bca158cdbce5acc25d7f44553252..bfbb2ded0782dbf4e177d35b00cca42e70e581e2 100644 (file)
@@ -24,6 +24,7 @@
 use option::Option::{self, Some, None};
 use result::Result::{self, Ok, Err};
 use str::{FromStr, StrExt};
+use slice::SliceExt;
 
 /// Provides intentionally-wrapped arithmetic on `T`.
 ///
@@ -1448,19 +1449,30 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
                                          -> Result<T, ParseIntError> {
     use self::IntErrorKind::*;
     use self::ParseIntError as PIE;
+
     assert!(radix >= 2 && radix <= 36,
            "from_str_radix_int: must lie in the range `[2, 36]` - found {}",
            radix);
 
+    if src.is_empty() {
+        return Err(PIE { kind: Empty });
+    }
+
     let is_signed_ty = T::from_u32(0) > T::min_value();
 
-    match src.slice_shift_char() {
-        Some(('-', "")) => Err(PIE { kind: Empty }),
-        Some(('-', src)) if is_signed_ty => {
+    // all valid digits are ascii, so we will just iterate over the utf8 bytes
+    // and cast them to chars. .to_digit() will safely return None for anything
+    // other than a valid ascii digit for a the given radix, including the first-byte
+    // of multi-byte sequences
+    let src = src.as_bytes();
+
+    match (src[0], &src[1..])  {
+        (b'-', digits) if digits.is_empty() => Err(PIE { kind: Empty }),
+        (b'-', digits) if is_signed_ty => {
             // The number is negative
             let mut result = T::from_u32(0);
-            for c in src.chars() {
-                let x = match c.to_digit(radix) {
+            for &c in digits {
+                let x = match (c as char).to_digit(radix) {
                     Some(x) => x,
                     None => return Err(PIE { kind: InvalidDigit }),
                 };
@@ -1475,11 +1487,14 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
             }
             Ok(result)
         },
-        Some((_, _)) => {
+        (c, digits) => {
             // The number is signed
-            let mut result = T::from_u32(0);
-            for c in src.chars() {
-                let x = match c.to_digit(radix) {
+            let mut result = match (c as char).to_digit(radix) {
+                Some(x) => T::from_u32(x),
+                None => return Err(PIE { kind: InvalidDigit }),
+            };
+            for &c in digits {
+                let x = match (c as char).to_digit(radix) {
                     Some(x) => x,
                     None => return Err(PIE { kind: InvalidDigit }),
                 };
@@ -1493,8 +1508,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
                 };
             }
             Ok(result)
-        },
-        None => Err(ParseIntError { kind: Empty }),
+        }
     }
 }
 
index 998f4b21ece7f8f8345ccac81ffcfe8e4fadbba2..a9baa2cc477f6c326923888cb80bfa3bc162eb05 100644 (file)
@@ -117,7 +117,14 @@ fn test_int_from_str_overflow() {
     }
 
     #[test]
-    fn test_int_from_minus_sign() {
-        assert_eq!("-".parse::<i32>().ok(), None);
+    fn test_invalid() {
+        assert_eq!("--129".parse::<i8>().ok(), None);
+        assert_eq!("Съешь".parse::<u8>().ok(), None);
+    }
+
+    #[test]
+    fn test_empty() {
+        assert_eq!("-".parse::<i8>().ok(), None);
+        assert_eq!("".parse::<u8>().ok(), None);
     }
 }
index 40a298f47648295962b082221deaa96f8182cff0..a0d06e5e1244a2559e3bd940f418b301f9769e58 100644 (file)
@@ -321,5 +321,7 @@ pub mod foo {
     E0432, // unresolved import
     E0433, // failed to resolve
     E0434, // can't capture dynamic environment in a fn item
-    E0435  // attempt to use a non-constant value in a constant
+    E0435, // attempt to use a non-constant value in a constant
+    E0437, // type is not a member of trait
+    E0438, // const is not a member of trait
 }
index e1afc33684ce65ea7b595d3b546feeace5405295..a3a0398e5ce1d58f5735d66066a70c2076f7580c 100644 (file)
@@ -123,6 +123,10 @@ pub enum ResolutionError<'a> {
     UndeclaredAssociatedType,
     /// error E0407: method is not a member of trait
     MethodNotMemberOfTrait(Name, &'a str),
+    /// error E0437: type is not a member of trait
+    TypeNotMemberOfTrait(Name, &'a str),
+    /// error E0438: const is not a member of trait
+    ConstNotMemberOfTrait(Name, &'a str),
     /// error E0408: variable `{}` from pattern #1 is not bound in pattern
     VariableNotBoundInPattern(Name, usize),
     /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
@@ -220,6 +224,18 @@ fn resolve_error<'b, 'a:'b, 'tcx:'a>(resolver: &'b Resolver<'a, 'tcx>, span: syn
                          method,
                          trait_);
         },
+        ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
+            span_err!(resolver.session, span, E0437,
+                         "type `{}` is not a member of trait `{}`",
+                         type_,
+                         trait_);
+        },
+        ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
+            span_err!(resolver.session, span, E0438,
+                         "const `{}` is not a member of trait `{}`",
+                         const_,
+                         trait_);
+        },
         ResolutionError::VariableNotBoundInPattern(variable_name, pattern_number) => {
             span_err!(resolver.session, span, E0408,
                          "variable `{}` from pattern #1 is not bound in pattern #{}",
@@ -2385,10 +2401,11 @@ fn resolve_implementation(&mut self,
                         for impl_item in impl_items {
                             match impl_item.node {
                                 ConstImplItem(..) => {
-                                    // If this is a trait impl, ensure the method
+                                    // If this is a trait impl, ensure the const
                                     // exists in trait
                                     this.check_trait_item(impl_item.ident.name,
-                                                          impl_item.span);
+                                                          impl_item.span,
+                                        |n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
                                     this.with_constant_rib(|this| {
                                         visit::walk_impl_item(this, impl_item);
                                     });
@@ -2397,7 +2414,8 @@ fn resolve_implementation(&mut self,
                                     // If this is a trait impl, ensure the method
                                     // exists in trait
                                     this.check_trait_item(impl_item.ident.name,
-                                                          impl_item.span);
+                                                          impl_item.span,
+                                        |n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
 
                                     // We also need a new scope for the method-
                                     // specific type parameters.
@@ -2410,10 +2428,11 @@ fn resolve_implementation(&mut self,
                                     });
                                 }
                                 TypeImplItem(ref ty) => {
-                                    // If this is a trait impl, ensure the method
+                                    // If this is a trait impl, ensure the type
                                     // exists in trait
                                     this.check_trait_item(impl_item.ident.name,
-                                                          impl_item.span);
+                                                          impl_item.span,
+                                        |n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
 
                                     this.visit_ty(ty);
                                 }
@@ -2426,15 +2445,15 @@ fn resolve_implementation(&mut self,
         });
     }
 
-    fn check_trait_item(&self, name: Name, span: Span) {
+    fn check_trait_item<F>(&self, name: Name, span: Span, err: F)
+        where F: FnOnce(Name, &str) -> ResolutionError {
         // If there is a TraitRef in scope for an impl, then the method must be in the trait.
         if let Some((did, ref trait_ref)) = self.current_trait_ref {
             if !self.trait_item_map.contains_key(&(name, did)) {
                 let path_str = path_names_to_string(&trait_ref.path, 0);
                 resolve_error(self,
                               span,
-                              ResolutionError::MethodNotMemberOfTrait(name,
-                                                                       &*path_str));
+                              err(name, &*path_str));
             }
         }
     }
index 6e6d3c8105d8f4597866b4f387aa646f6b2d5af6..28802d323c692d2ddf491991e50197e71c46bc3e 100644 (file)
@@ -2099,28 +2099,32 @@ pub fn parse_bottom_expr(&mut self) -> PResult<P<Expr>> {
                     return self.parse_if_expr();
                 }
                 if try!(self.eat_keyword(keywords::For) ){
-                    return self.parse_for_expr(None);
+                    let lo = self.last_span.lo;
+                    return self.parse_for_expr(None, lo);
                 }
                 if try!(self.eat_keyword(keywords::While) ){
-                    return self.parse_while_expr(None);
+                    let lo = self.last_span.lo;
+                    return self.parse_while_expr(None, lo);
                 }
                 if self.token.is_lifetime() {
                     let lifetime = self.get_lifetime();
+                    let lo = self.span.lo;
                     try!(self.bump());
                     try!(self.expect(&token::Colon));
                     if try!(self.eat_keyword(keywords::While) ){
-                        return self.parse_while_expr(Some(lifetime))
+                        return self.parse_while_expr(Some(lifetime), lo)
                     }
                     if try!(self.eat_keyword(keywords::For) ){
-                        return self.parse_for_expr(Some(lifetime))
+                        return self.parse_for_expr(Some(lifetime), lo)
                     }
                     if try!(self.eat_keyword(keywords::Loop) ){
-                        return self.parse_loop_expr(Some(lifetime))
+                        return self.parse_loop_expr(Some(lifetime), lo)
                     }
                     return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
                 }
                 if try!(self.eat_keyword(keywords::Loop) ){
-                    return self.parse_loop_expr(None);
+                    let lo = self.last_span.lo;
+                    return self.parse_loop_expr(None, lo);
                 }
                 if try!(self.eat_keyword(keywords::Continue) ){
                     let lo = self.span.lo;
@@ -2892,48 +2896,48 @@ pub fn parse_else_expr(&mut self) -> PResult<P<Expr>> {
     }
 
     /// Parse a 'for' .. 'in' expression ('for' token already eaten)
-    pub fn parse_for_expr(&mut self, opt_ident: Option<ast::Ident>) -> PResult<P<Expr>> {
+    pub fn parse_for_expr(&mut self, opt_ident: Option<ast::Ident>,
+                          span_lo: BytePos) -> PResult<P<Expr>> {
         // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
 
-        let lo = self.last_span.lo;
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect_keyword(keywords::In));
         let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let loop_block = try!(self.parse_block());
         let hi = self.last_span.hi;
 
-        Ok(self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident)))
+        Ok(self.mk_expr(span_lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident)))
     }
 
     /// Parse a 'while' or 'while let' expression ('while' token already eaten)
-    pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> PResult<P<Expr>> {
+    pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>,
+                            span_lo: BytePos) -> PResult<P<Expr>> {
         if self.token.is_keyword(keywords::Let) {
-            return self.parse_while_let_expr(opt_ident);
+            return self.parse_while_let_expr(opt_ident, span_lo);
         }
-        let lo = self.last_span.lo;
         let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let body = try!(self.parse_block());
         let hi = body.span.hi;
-        return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident)));
+        return Ok(self.mk_expr(span_lo, hi, ExprWhile(cond, body, opt_ident)));
     }
 
     /// Parse a 'while let' expression ('while' token already eaten)
-    pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::Ident>) -> PResult<P<Expr>> {
-        let lo = self.last_span.lo;
+    pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::Ident>,
+                                span_lo: BytePos) -> PResult<P<Expr>> {
         try!(self.expect_keyword(keywords::Let));
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect(&token::Eq));
         let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let body = try!(self.parse_block());
         let hi = body.span.hi;
-        return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident)));
+        return Ok(self.mk_expr(span_lo, hi, ExprWhileLet(pat, expr, body, opt_ident)));
     }
 
-    pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> PResult<P<Expr>> {
-        let lo = self.last_span.lo;
+    pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>,
+                           span_lo: BytePos) -> PResult<P<Expr>> {
         let body = try!(self.parse_block());
         let hi = body.span.hi;
-        Ok(self.mk_expr(lo, hi, ExprLoop(body, opt_ident)))
+        Ok(self.mk_expr(span_lo, hi, ExprLoop(body, opt_ident)))
     }
 
     fn parse_match_expr(&mut self) -> PResult<P<Expr>> {
diff --git a/src/test/compile-fail/issue-15919.rs b/src/test/compile-fail/issue-15919.rs
new file mode 100644 (file)
index 0000000..df7e7c1
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern: too big for the current architecture
+
+#[cfg(target_pointer_width = "32")]
+fn main() {
+    let x = [0usize; 0xffff_ffff];
+}
+
+#[cfg(target_pointer_width = "64")]
+fn main() {
+    let x = [0usize; 0xffff_ffff_ffff_ffff];
+}
diff --git a/src/test/compile-fail/issue-27042.rs b/src/test/compile-fail/issue-27042.rs
new file mode 100644 (file)
index 0000000..f31389f
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #27042. Test that a loop's label is included in its span.
+
+fn main() {
+    let _: i32 =
+        'a: //~ ERROR mismatched types
+        loop { break };
+    let _: i32 =
+        'b: //~ ERROR mismatched types
+        while true { break };
+    let _: i32 =
+        'c: //~ ERROR mismatched types
+        for _ in None { break };
+    let _: i32 =
+        'd: //~ ERROR mismatched types
+        while let Some(_) = None { break };
+}
diff --git a/src/test/compile-fail/trait-impl-can-not-have-untraitful-items.rs b/src/test/compile-fail/trait-impl-can-not-have-untraitful-items.rs
new file mode 100644 (file)
index 0000000..0ed4e62
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait A { }
+
+impl A for isize {
+    const BAR: () = (); //~ ERROR const `BAR` is not a member of trait `A`
+    type Baz = (); //~ ERROR type `Baz` is not a member of trait `A`
+    fn foo(&self) { } //~ ERROR method `foo` is not a member of trait `A`
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/trait-impl-can-not-have-untraitful-methods.rs b/src/test/compile-fail/trait-impl-can-not-have-untraitful-methods.rs
deleted file mode 100644 (file)
index 3538c7f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-trait A { }
-
-impl A for isize {
-    fn foo(&self) { } //~ ERROR method `foo` is not a member of trait `A`
-}
-
-fn main() { }