about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-06-14 00:40:10 +0000
committerbors <bors@rust-lang.org>2017-06-14 00:40:10 +0000
commite40ef964fe491b19c22dfb8dd36d1eab14223c36 (patch)
tree03f28fa7e4ab70baca8217f633446e0811f3a32b
parent03abb1bd70ac56e4aba0684bab819892a0157843 (diff)
parent9242f22666e44d525e57a6f4ade91be450f0ee2e (diff)
downloadrust-e40ef964fe491b19c22dfb8dd36d1eab14223c36.tar.gz
rust-e40ef964fe491b19c22dfb8dd36d1eab14223c36.zip
Auto merge of #42644 - frewsxcv:rollup, r=frewsxcv
Rollup of 6 pull requests

- Successful merges: #42408, #42428, #42496, #42597, #42636, #42638
- Failed merges: #42612
-rw-r--r--src/doc/unstable-book/src/SUMMARY.md1
-rw-r--r--src/doc/unstable-book/src/library-features/ord-max-min.md7
-rw-r--r--src/grammar/lexer.l2
-rw-r--r--src/libcollections/tests/lib.rs1
-rw-r--r--src/libcollections/tests/str.rs42
-rw-r--r--src/libcore/cmp.rs44
-rw-r--r--src/libcore/str/mod.rs71
-rw-r--r--src/libcore/tests/cmp.rs10
-rw-r--r--src/libcore/tests/lib.rs1
-rw-r--r--src/librustc/hir/check_attr.rs29
-rw-r--r--src/librustc_typeck/check/mod.rs32
-rw-r--r--src/librustc_typeck/diagnostics.rs21
-rw-r--r--src/libstd/thread/mod.rs14
-rw-r--r--src/test/compile-fail/E0617.rs32
-rw-r--r--src/test/compile-fail/variadic-ffi-3.rs12
15 files changed, 233 insertions, 86 deletions
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
index 2b3ef338fad..b278b5dbb2c 100644
--- a/src/doc/unstable-book/src/SUMMARY.md
+++ b/src/doc/unstable-book/src/SUMMARY.md
@@ -165,6 +165,7 @@
     - [n16](library-features/n16.md)
     - [never_type_impls](library-features/never-type-impls.md)
     - [nonzero](library-features/nonzero.md)
+    - [ord_max_min](library-features/ord-max-min.md)
     - [offset_to](library-features/offset-to.md)
     - [once_poison](library-features/once-poison.md)
     - [oom](library-features/oom.md)
diff --git a/src/doc/unstable-book/src/library-features/ord-max-min.md b/src/doc/unstable-book/src/library-features/ord-max-min.md
new file mode 100644
index 00000000000..564cd1ac30b
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/ord-max-min.md
@@ -0,0 +1,7 @@
+# `ord-max-min`
+
+The tracking issue for this feature is: [#25663]
+
+[#25663]: https://github.com/rust-lang/rust/issues/25663
+
+------------------------
diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l
index 77737c99496..91652bfdf24 100644
--- a/src/grammar/lexer.l
+++ b/src/grammar/lexer.l
@@ -126,7 +126,7 @@ while    { return WHILE; }
 {ident}  { return IDENT; }
 
 0x[0-9a-fA-F_]+                                    { BEGIN(suffix); return LIT_INTEGER; }
-0o[0-8_]+                                          { BEGIN(suffix); return LIT_INTEGER; }
+0o[0-7_]+                                          { BEGIN(suffix); return LIT_INTEGER; }
 0b[01_]+                                           { BEGIN(suffix); return LIT_INTEGER; }
 [0-9][0-9_]*                                       { BEGIN(suffix); return LIT_INTEGER; }
 [0-9][0-9_]*\.(\.|[a-zA-Z])    { yyless(yyleng - 2); BEGIN(suffix); return LIT_INTEGER; }
diff --git a/src/libcollections/tests/lib.rs b/src/libcollections/tests/lib.rs
index 5f5217b73c2..c6f0b4436bb 100644
--- a/src/libcollections/tests/lib.rs
+++ b/src/libcollections/tests/lib.rs
@@ -24,6 +24,7 @@
 #![feature(repr_align)]
 #![feature(slice_rotate)]
 #![feature(splice)]
+#![feature(str_checked_slicing)]
 #![feature(str_escape)]
 #![feature(test)]
 #![feature(unboxed_closures)]
diff --git a/src/libcollections/tests/str.rs b/src/libcollections/tests/str.rs
index c9b7104fec4..9d8ca38b20e 100644
--- a/src/libcollections/tests/str.rs
+++ b/src/libcollections/tests/str.rs
@@ -358,6 +358,48 @@ fn test_slice_fail() {
     &"中华Việt Nam"[0..2];
 }
 
+#[test]
+#[should_panic]
+fn test_str_slice_rangetoinclusive_max_panics() {
+    &"hello"[...usize::max_value()];
+}
+
+#[test]
+#[should_panic]
+fn test_str_slice_rangeinclusive_max_panics() {
+    &"hello"[1...usize::max_value()];
+}
+
+#[test]
+#[should_panic]
+fn test_str_slicemut_rangetoinclusive_max_panics() {
+    let mut s = "hello".to_owned();
+    let s: &mut str = &mut s;
+    &mut s[...usize::max_value()];
+}
+
+#[test]
+#[should_panic]
+fn test_str_slicemut_rangeinclusive_max_panics() {
+    let mut s = "hello".to_owned();
+    let s: &mut str = &mut s;
+    &mut s[1...usize::max_value()];
+}
+
+#[test]
+fn test_str_get_maxinclusive() {
+    let mut s = "hello".to_owned();
+    {
+        let s: &str = &s;
+        assert_eq!(s.get(...usize::max_value()), None);
+        assert_eq!(s.get(1...usize::max_value()), None);
+    }
+    {
+        let s: &mut str = &mut s;
+        assert_eq!(s.get(...usize::max_value()), None);
+        assert_eq!(s.get(1...usize::max_value()), None);
+    }
+}
 
 #[test]
 fn test_is_char_boundary() {
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index 661cf73c7f3..6f35d0417f1 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -443,6 +443,42 @@ pub trait Ord: Eq + PartialOrd<Self> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn cmp(&self, other: &Self) -> Ordering;
+
+    /// Compares and returns the maximum of two values.
+    ///
+    /// Returns the second argument if the comparison determines them to be equal.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ord_max_min)]
+    ///
+    /// assert_eq!(2, 1.max(2));
+    /// assert_eq!(2, 2.max(2));
+    /// ```
+    #[unstable(feature = "ord_max_min", issue = "25663")]
+    fn max(self, other: Self) -> Self
+    where Self: Sized {
+        if other >= self { other } else { self }
+    }
+
+    /// Compares and returns the minimum of two values.
+    ///
+    /// Returns the first argument if the comparison determines them to be equal.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ord_max_min)]
+    ///
+    /// assert_eq!(1, 1.min(2));
+    /// assert_eq!(2, 2.min(2));
+    /// ```
+    #[unstable(feature = "ord_max_min", issue = "25663")]
+    fn min(self, other: Self) -> Self
+    where Self: Sized {
+        if self <= other { self } else { other }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -678,6 +714,8 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
 ///
 /// Returns the first argument if the comparison determines them to be equal.
 ///
+/// Internally uses an alias to `Ord::min`.
+///
 /// # Examples
 ///
 /// ```
@@ -689,13 +727,15 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn min<T: Ord>(v1: T, v2: T) -> T {
-    if v1 <= v2 { v1 } else { v2 }
+    v1.min(v2)
 }
 
 /// Compares and returns the maximum of two values.
 ///
 /// Returns the second argument if the comparison determines them to be equal.
 ///
+/// Internally uses an alias to `Ord::max`.
+///
 /// # Examples
 ///
 /// ```
@@ -707,7 +747,7 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn max<T: Ord>(v1: T, v2: T) -> T {
-    if v2 >= v1 { v2 } else { v1 }
+    v1.max(v2)
 }
 
 // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 547a4899c71..34aca592b1e 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -1617,12 +1617,7 @@ mod traits {
 
         #[inline]
         fn index(&self, index: ops::RangeTo<usize>) -> &str {
-            // is_char_boundary checks that the index is in [0, .len()]
-            if self.is_char_boundary(index.end) {
-                unsafe { self.slice_unchecked(0, index.end) }
-            } else {
-                super::slice_error_fail(self, 0, index.end)
-            }
+            index.index(self)
         }
     }
 
@@ -1636,12 +1631,7 @@ mod traits {
     impl ops::IndexMut<ops::RangeTo<usize>> for str {
         #[inline]
         fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
-            // is_char_boundary checks that the index is in [0, .len()]
-            if self.is_char_boundary(index.end) {
-                unsafe { self.slice_mut_unchecked(0, index.end) }
-            } else {
-                super::slice_error_fail(self, 0, index.end)
-            }
+            index.index_mut(self)
         }
     }
 
@@ -1657,12 +1647,7 @@ mod traits {
 
         #[inline]
         fn index(&self, index: ops::RangeFrom<usize>) -> &str {
-            // is_char_boundary checks that the index is in [0, .len()]
-            if self.is_char_boundary(index.start) {
-                unsafe { self.slice_unchecked(index.start, self.len()) }
-            } else {
-                super::slice_error_fail(self, index.start, self.len())
-            }
+            index.index(self)
         }
     }
 
@@ -1676,13 +1661,7 @@ mod traits {
     impl ops::IndexMut<ops::RangeFrom<usize>> for str {
         #[inline]
         fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
-            // is_char_boundary checks that the index is in [0, .len()]
-            if self.is_char_boundary(index.start) {
-                let len = self.len();
-                unsafe { self.slice_mut_unchecked(index.start, len) }
-            } else {
-                super::slice_error_fail(self, index.start, self.len())
-            }
+            index.index_mut(self)
         }
     }
 
@@ -1724,9 +1703,7 @@ mod traits {
 
         #[inline]
         fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
-            assert!(index.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
-            self.index(index.start .. index.end+1)
+            index.index(self)
         }
     }
 
@@ -1738,9 +1715,7 @@ mod traits {
 
         #[inline]
         fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
-            assert!(index.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
-            self.index(.. index.end+1)
+            index.index(self)
         }
     }
 
@@ -1750,9 +1725,7 @@ mod traits {
     impl ops::IndexMut<ops::RangeInclusive<usize>> for str {
         #[inline]
         fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
-            assert!(index.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
-            self.index_mut(index.start .. index.end+1)
+            index.index_mut(self)
         }
     }
     #[unstable(feature = "inclusive_range",
@@ -1761,9 +1734,7 @@ mod traits {
     impl ops::IndexMut<ops::RangeToInclusive<usize>> for str {
         #[inline]
         fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
-            assert!(index.end != usize::max_value(),
-                "attempted to index str up to maximum usize");
-            self.index_mut(.. index.end+1)
+            index.index_mut(self)
         }
     }
 
@@ -1886,6 +1857,7 @@ mod traits {
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+            // is_char_boundary checks that the index is in [0, .len()]
             if slice.is_char_boundary(self.end) {
                 unsafe { self.get_unchecked_mut(slice) }
             } else {
@@ -1932,6 +1904,7 @@ mod traits {
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+            // is_char_boundary checks that the index is in [0, .len()]
             if slice.is_char_boundary(self.start) {
                 unsafe { self.get_unchecked_mut(slice) }
             } else {
@@ -1945,11 +1918,19 @@ mod traits {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
-            (self.start..self.end+1).get(slice)
+            if let Some(end) = self.end.checked_add(1) {
+                (self.start..end).get(slice)
+            } else {
+                None
+            }
         }
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            (self.start..self.end+1).get_mut(slice)
+            if let Some(end) = self.end.checked_add(1) {
+                (self.start..end).get_mut(slice)
+            } else {
+                None
+            }
         }
         #[inline]
         unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
@@ -1961,10 +1942,14 @@ mod traits {
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
+            assert!(self.end != usize::max_value(),
+                "attempted to index str up to maximum usize");
             (self.start..self.end+1).index(slice)
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+            assert!(self.end != usize::max_value(),
+                "attempted to index str up to maximum usize");
             (self.start..self.end+1).index_mut(slice)
         }
     }
@@ -1976,7 +1961,7 @@ mod traits {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
-            if slice.is_char_boundary(self.end + 1) {
+            if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
                 Some(unsafe { self.get_unchecked(slice) })
             } else {
                 None
@@ -1984,7 +1969,7 @@ mod traits {
         }
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if slice.is_char_boundary(self.end + 1) {
+            if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
                 Some(unsafe { self.get_unchecked_mut(slice) })
             } else {
                 None
@@ -2002,11 +1987,15 @@ mod traits {
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
+            assert!(self.end != usize::max_value(),
+                "attempted to index str up to maximum usize");
             let end = self.end + 1;
             self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+            assert!(self.end != usize::max_value(),
+                "attempted to index str up to maximum usize");
             if slice.is_char_boundary(self.end) {
                 unsafe { self.get_unchecked_mut(slice) }
             } else {
diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs
index e3c65ad8b33..8c5179f5993 100644
--- a/src/libcore/tests/cmp.rs
+++ b/src/libcore/tests/cmp.rs
@@ -29,6 +29,16 @@ fn test_mut_int_totalord() {
 }
 
 #[test]
+fn test_ord_max_min() {
+    assert_eq!(1.max(2), 2);
+    assert_eq!(2.max(1), 2);
+    assert_eq!(1.min(2), 1);
+    assert_eq!(2.min(1), 1);
+    assert_eq!(1.max(1), 1);
+    assert_eq!(1.min(1), 1);
+}
+
+#[test]
 fn test_ordering_reverse() {
     assert_eq!(Less.reverse(), Greater);
     assert_eq!(Equal.reverse(), Equal);
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 505e51fa80b..77a9307f43e 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -26,6 +26,7 @@
 #![feature(iter_rfind)]
 #![feature(libc)]
 #![feature(nonzero)]
+#![feature(ord_max_min)]
 #![feature(rand)]
 #![feature(raw)]
 #![feature(sip_hash_13)]
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index f553c03d09b..3034242b594 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -8,6 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! This module implements some validity checks for attributes.
+//! In particular it verifies that `#[inline]` and `#[repr]` attributes are
+//! attached to items that actually support them and if there are
+//! conflicts between multiple such attributes attached to the same
+//! item.
+
 use session::Session;
 
 use syntax::ast;
@@ -40,6 +46,18 @@ struct CheckAttrVisitor<'a> {
 }
 
 impl<'a> CheckAttrVisitor<'a> {
+    /// Check any attribute.
+    fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
+        if let Some(name) = attr.name() {
+            match &*name.as_str() {
+                "inline" => self.check_inline(attr, target),
+                "repr" => self.check_repr(attr, target),
+                _ => (),
+            }
+        }
+    }
+
+    /// Check if an `#[inline]` is applied to a function.
     fn check_inline(&self, attr: &ast::Attribute, target: Target) {
         if target != Target::Fn {
             struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function")
@@ -48,6 +66,7 @@ impl<'a> CheckAttrVisitor<'a> {
         }
     }
 
+    /// Check if an `#[repr]` attr is valid.
     fn check_repr(&self, attr: &ast::Attribute, target: Target) {
         let words = match attr.meta_item_list() {
             Some(words) => words,
@@ -135,16 +154,6 @@ impl<'a> CheckAttrVisitor<'a> {
                              "conflicting packed and align representation hints").emit();
         }
     }
-
-    fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
-        if let Some(name) = attr.name() {
-            match &*name.as_str() {
-                "inline" => self.check_inline(attr, target),
-                "repr" => self.check_repr(attr, target),
-                _ => (),
-            }
-        }
-    }
 }
 
 impl<'a> Visitor<'a> for CheckAttrVisitor<'a> {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 880137f7c71..c12df083c30 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2553,42 +2553,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // We also need to make sure we at least write the ty of the other
         // arguments which we skipped above.
         if variadic {
+            fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
+                type_error_struct!(s, span, t, E0617,
+                                   "can't pass `{}` to variadic function, cast to `{}`",
+                                   t, cast_ty).emit();
+            }
+
             for arg in args.iter().skip(expected_arg_count) {
                 let arg_ty = self.check_expr(&arg);
 
                 // There are a few types which get autopromoted when passed via varargs
                 // in C but we just error out instead and require explicit casts.
-                let arg_ty = self.structurally_resolved_type(arg.span,
-                                                             arg_ty);
+                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
                 match arg_ty.sty {
                     ty::TyFloat(ast::FloatTy::F32) => {
-                        self.type_error_message(arg.span, |t| {
-                            format!("can't pass an `{}` to variadic \
-                                     function, cast to `c_double`", t)
-                        }, arg_ty);
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
                     }
                     ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
-                        self.type_error_message(arg.span, |t| {
-                            format!("can't pass `{}` to variadic \
-                                     function, cast to `c_int`",
-                                           t)
-                        }, arg_ty);
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
                     }
                     ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
-                        self.type_error_message(arg.span, |t| {
-                            format!("can't pass `{}` to variadic \
-                                     function, cast to `c_uint`",
-                                           t)
-                        }, arg_ty);
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
                     }
                     ty::TyFnDef(.., f) => {
                         let ptr_ty = self.tcx.mk_fn_ptr(f);
                         let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
-                        self.type_error_message(arg.span,
-                                                |t| {
-                            format!("can't pass `{}` to variadic \
-                                     function, cast to `{}`", t, ptr_ty)
-                        }, arg_ty);
+                        variadic_error(tcx.sess, arg.span, arg_ty, &format!("{}", ptr_ty));
                     }
                     _ => {}
                 }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 6ccfab0a324..76c664d7997 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4152,6 +4152,27 @@ println!("x: {}, y: {}", variable.x, variable.y);
 For more information see The Rust Book: https://doc.rust-lang.org/book/
 "##,
 
+E0617: r##"
+Attempted to pass an invalid type of variable into a variadic function.
+
+Erroneous code example:
+
+```compile_fail,E0617
+extern {
+    fn printf(c: *const i8, ...);
+}
+
+unsafe {
+    printf(::std::ptr::null(), 0f32);
+    // error: can't pass an `f32` to variadic function, cast to `c_double`
+}
+```
+
+To fix this error, you need to pass variables corresponding to C types as much
+as possible. For better explanations, see The Rust Book:
+https://doc.rust-lang.org/book/
+"##,
+
 }
 
 register_diagnostics! {
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 64c31c2a681..dda11e50380 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -787,12 +787,16 @@ pub fn park_timeout_ms(ms: u32) {
 ///
 /// let timeout = Duration::from_secs(2);
 /// let beginning_park = Instant::now();
-/// park_timeout(timeout);
 ///
-/// while beginning_park.elapsed() < timeout {
-///     println!("restarting park_timeout after {:?}", beginning_park.elapsed());
-///     let timeout = timeout - beginning_park.elapsed();
-///     park_timeout(timeout);
+/// let mut timeout_remaining = timeout;
+/// loop {
+///     park_timeout(timeout_remaining);
+///     let elapsed = beginning_park.elapsed();
+///     if elapsed >= timeout {
+///         break;
+///     }
+///     println!("restarting park_timeout after {:?}", elapsed);
+///     timeout_remaining = timeout - elapsed;
 /// }
 /// ```
 ///
diff --git a/src/test/compile-fail/E0617.rs b/src/test/compile-fail/E0617.rs
new file mode 100644
index 00000000000..7b769ff4ae2
--- /dev/null
+++ b/src/test/compile-fail/E0617.rs
@@ -0,0 +1,32 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+extern {
+    fn printf(c: *const i8, ...);
+}
+
+fn main() {
+    unsafe {
+        printf(::std::ptr::null(), 0f32);
+        //~^ ERROR can't pass `f32` to variadic function, cast to `c_double` [E0617]
+        printf(::std::ptr::null(), 0i8);
+        //~^ ERROR can't pass `i8` to variadic function, cast to `c_int` [E0617]
+        printf(::std::ptr::null(), 0i16);
+        //~^ ERROR can't pass `i16` to variadic function, cast to `c_int` [E0617]
+        printf(::std::ptr::null(), 0u8);
+        //~^ ERROR can't pass `u8` to variadic function, cast to `c_uint` [E0617]
+        printf(::std::ptr::null(), 0u16);
+        //~^ ERROR can't pass `u16` to variadic function, cast to `c_uint` [E0617]
+        printf(::std::ptr::null(), printf);
+        //~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function, cast to `unsafe extern "C" fn(*const i8, ...)` [E0617]
+    }
+}
diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs
index 565d8549b37..fb102027180 100644
--- a/src/test/compile-fail/variadic-ffi-3.rs
+++ b/src/test/compile-fail/variadic-ffi-3.rs
@@ -35,11 +35,11 @@ fn main() {
         //~| found type `extern "C" fn(isize, u8) {bar}`
         //~| NOTE: expected variadic fn, found non-variadic function
 
-        foo(1, 2, 3f32); //~ ERROR: can't pass an `f32` to variadic function, cast to `c_double`
-        foo(1, 2, true); //~ ERROR: can't pass `bool` to variadic function, cast to `c_int`
-        foo(1, 2, 1i8); //~ ERROR: can't pass `i8` to variadic function, cast to `c_int`
-        foo(1, 2, 1u8); //~ ERROR: can't pass `u8` to variadic function, cast to `c_uint`
-        foo(1, 2, 1i16); //~ ERROR: can't pass `i16` to variadic function, cast to `c_int`
-        foo(1, 2, 1u16); //~ ERROR: can't pass `u16` to variadic function, cast to `c_uint`
+        foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function, cast to `c_double`
+        foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function, cast to `c_int`
+        foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function, cast to `c_int`
+        foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function, cast to `c_uint`
+        foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function, cast to `c_int`
+        foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function, cast to `c_uint`
     }
 }