diff --git a/src/doc/index.md b/src/doc/index.md index f8a1ec134d924..71dfcf0b067ec 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -17,7 +17,7 @@ the language. [**The Rust Reference**][ref]. While Rust does not have a specification, the reference tries to describe its working in -detail. It tends to be out of date. +detail. It is accurate, but not necessarily complete. [**Standard Library API Reference**][api]. Documentation for the standard library. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e94e93158c47a..ebf8c96def7cc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -48,6 +48,7 @@ use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; +use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; use hir; use hir::itemlikevisit::ItemLikeVisitor; @@ -1887,7 +1888,7 @@ impl<'tcx> TyS<'tcx> { /// Iterator that walks the immediate children of `self`. Hence /// `Foo, u32>` yields the sequence `[Bar, u32]` /// (but not `i32`, like `walk`). - pub fn walk_shallow(&'tcx self) -> IntoIter> { + pub fn walk_shallow(&'tcx self) -> AccIntoIter> { walk::walk_shallow(self) } diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index a6ecfd2fb7066..2f9468dbe5887 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -12,17 +12,22 @@ //! WARNING: this does not keep track of the region depth. use ty::{self, Ty}; -use std::iter::Iterator; -use std::vec::IntoIter; +use rustc_data_structures::small_vec::SmallVec; +use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; + +// The TypeWalker's stack is hot enough that it's worth going to some effort to +// avoid heap allocations. +pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8]; +pub type TypeWalkerStack<'tcx> = SmallVec>; pub struct TypeWalker<'tcx> { - stack: Vec>, + stack: TypeWalkerStack<'tcx>, last_subtree: usize, } impl<'tcx> TypeWalker<'tcx> { pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: vec![ty], last_subtree: 1, } + TypeWalker { stack: SmallVec::one(ty), last_subtree: 1, } } /// Skips the subtree of types corresponding to the last type @@ -61,8 +66,8 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { } } -pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { - let mut stack = vec![]; +pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter> { + let mut stack = SmallVec::new(); push_subtypes(&mut stack, ty); stack.into_iter() } @@ -73,7 +78,7 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { // known to be significant to any code, but it seems like the // natural order one would expect (basically, the order of the // types as they are written). -fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { +fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => { @@ -112,7 +117,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { } } -fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { +fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) { stack.push(sig.0.output); stack.extend(sig.0.inputs.iter().cloned().rev()); } diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 565a3c443a34a..4e2b378602102 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -130,6 +130,18 @@ impl SmallVec { self.set_len(len + 1); } } + + pub fn truncate(&mut self, len: usize) { + unsafe { + while len < self.len() { + // Decrement len before the drop_in_place(), so a panic on Drop + // doesn't re-drop the just-failed value. + let newlen = self.len() - 1; + self.set_len(newlen); + ::std::ptr::drop_in_place(self.get_unchecked_mut(newlen)); + } + } + } } impl Deref for SmallVec { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 4edf0011cb390..5839c606566c3 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -102,6 +102,7 @@ enum CastError { /// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`) SizedUnsizedCast, IllegalCast, + NeedDeref, NeedViaPtr, NeedViaThinPtr, NeedViaInt, @@ -138,6 +139,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) { match e { + CastError::NeedDeref => { + let cast_ty = fcx.ty_to_string(self.cast_ty); + let mut err = fcx.type_error_struct(self.cast_span, + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + cast_ty) + }, + self.expr_ty); + err.span_label(self.expr.span, + &format!("cannot cast `{}` as `{}`", + fcx.ty_to_string(self.expr_ty), + cast_ty)); + if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) { + err.span_label(self.expr.span, + &format!("did you mean `*{}`?", snippet)); + } + err.emit(); + } CastError::NeedViaThinPtr | CastError::NeedViaPtr => { let mut err = fcx.type_error_struct(self.span, @@ -390,8 +410,28 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), - (RPtr(_), Int(_)) | - (RPtr(_), Float) => Err(CastError::NeedViaPtr), + (RPtr(p), Int(_)) | + (RPtr(p), Float) => { + match p.ty.sty { + ty::TypeVariants::TyInt(_) | + ty::TypeVariants::TyUint(_) | + ty::TypeVariants::TyFloat(_) => { + Err(CastError::NeedDeref) + } + ty::TypeVariants::TyInfer(t) => { + match t { + ty::InferTy::IntVar(_) | + ty::InferTy::FloatVar(_) | + ty::InferTy::FreshIntTy(_) | + ty::InferTy::FreshFloatTy(_) => { + Err(CastError::NeedDeref) + } + _ => Err(CastError::NeedViaPtr), + } + } + _ => Err(CastError::NeedViaPtr), + } + } // * -> ptr (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), diff --git a/src/libstd/env.rs b/src/libstd/env.rs index e29dbe35c5a59..baa2b5d284622 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -546,17 +546,23 @@ pub fn current_exe() -> io::Result { os_imp::current_exe() } -/// An iterator over the arguments of a process, yielding a `String` value +/// An iterator over the arguments of a process, yielding a [`String`] value /// for each argument. /// -/// This structure is created through the `std::env::args` method. +/// This structure is created through the [`std::env::args`] method. +/// +/// [`String`]: ../string/struct.String.html +/// [`std::env::args`]: ./fn.args.html #[stable(feature = "env", since = "1.0.0")] pub struct Args { inner: ArgsOs } -/// An iterator over the arguments of a process, yielding an `OsString` value +/// An iterator over the arguments of a process, yielding an [`OsString`] value /// for each argument. /// -/// This structure is created through the `std::env::args_os` method. +/// This structure is created through the [`std::env::args_os`] method. +/// +/// [`OsString`]: ../ffi/struct.OsString.html +/// [`std::env::args_os`]: ./fn.args_os.html #[stable(feature = "env", since = "1.0.0")] pub struct ArgsOs { inner: sys::args::Args } @@ -571,7 +577,7 @@ pub struct ArgsOs { inner: sys::args::Args } /// /// The returned iterator will panic during iteration if any argument to the /// process is not valid unicode. If this is not desired, -/// use the `args_os` function instead. +/// use the [`args_os`] function instead. /// /// # Examples /// @@ -583,6 +589,8 @@ pub struct ArgsOs { inner: sys::args::Args } /// println!("{}", argument); /// } /// ``` +/// +/// [`args_os`]: ./fn.args_os.html #[stable(feature = "env", since = "1.0.0")] pub fn args() -> Args { Args { inner: args_os() } diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 1c016015b7928..0328012ee5726 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -194,6 +194,14 @@ impl SocketAddr { impl SocketAddrV4 { /// Creates a new socket address from the (ip, port) pair. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 { SocketAddrV4 { @@ -207,6 +215,15 @@ impl SocketAddrV4 { } /// Returns the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ip(&self) -> &Ipv4Addr { unsafe { @@ -215,18 +232,47 @@ impl SocketAddrV4 { } /// Change the IP address associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1)); + /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1)); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_ip(&mut self, new_ip: Ipv4Addr) { self.inner.sin_addr = *new_ip.as_inner() } /// Returns the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// assert_eq!(socket.port(), 8080); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn port(&self) -> u16 { ntoh(self.inner.sin_port) } /// Change the port number associated with this socket address. + /// + /// # Examples + /// + /// ``` + /// use std::net::{SocketAddrV4, Ipv4Addr}; + /// + /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); + /// socket.set_port(4242); + /// assert_eq!(socket.port(), 4242); + /// ``` #[stable(feature = "sockaddr_setters", since = "1.9.0")] pub fn set_port(&mut self, new_port: u16) { self.inner.sin_port = hton(new_port); diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 1dbad9e30e3ad..b98f464c90227 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -115,4 +115,9 @@ fn main() let _ = cf as *const Bar; //~^ ERROR casting //~^^ NOTE vtable kinds + + vec![0.0].iter().map(|s| s as f32).collect::>(); + //~^ ERROR casting `&{float}` as `f32` is invalid + //~| NOTE cannot cast `&{float}` as `f32` + //~| NOTE did you mean `*s`? } diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs new file mode 100644 index 0000000000000..c4366ea11e3f6 --- /dev/null +++ b/src/test/incremental/hashes/struct_constructors.rs @@ -0,0 +1,254 @@ +// 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. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for struct constructor expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +struct RegularStruct { + x: i32, + y: i64, + z: i16, +} + +// Change field value (regular struct) ----------------------------------------- +#[cfg(cfail1)] +fn change_field_value_regular_struct() -> RegularStruct { + RegularStruct { + x: 0, + y: 1, + z: 2, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_value_regular_struct() -> RegularStruct { + RegularStruct { + x: 0, + y: 2, + z: 2, + } +} + + + +// Change field order (regular struct) ----------------------------------------- +#[cfg(cfail1)] +fn change_field_order_regular_struct() -> RegularStruct { + RegularStruct { + x: 3, + y: 4, + z: 5, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_order_regular_struct() -> RegularStruct { + RegularStruct { + y: 4, + x: 3, + z: 5, + } +} + + + +// Add field (regular struct) -------------------------------------------------- +#[cfg(cfail1)] +fn add_field_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + .. struct1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn add_field_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + y: 8, + .. struct1 + } +} + + + +// Change field label (regular struct) ----------------------------------------- +#[cfg(cfail1)] +fn change_field_label_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + y: 9, + .. struct1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_label_regular_struct() -> RegularStruct { + let struct1 = RegularStruct { + x: 3, + y: 4, + z: 5, + }; + + RegularStruct { + x: 7, + z: 9, + .. struct1 + } +} + + + +struct RegularStruct2 { + x: i8, + y: i8, + z: i8, +} + +// Change constructor path (regular struct) ------------------------------------ +#[cfg(cfail1)] +fn change_constructor_path_regular_struct() { + let _ = RegularStruct { + x: 0, + y: 1, + z: 2, + }; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_constructor_path_regular_struct() { + let _ = RegularStruct2 { + x: 0, + y: 1, + z: 2, + }; +} + + + +// Change constructor path indirectly (regular struct) ------------------------- +mod change_constructor_path_indirectly_regular_struct { + #[cfg(cfail1)] + use super::RegularStruct as Struct; + #[cfg(not(cfail1))] + use super::RegularStruct2 as Struct; + + fn function() -> Struct { + Struct { + x: 0, + y: 1, + z: 2, + } + } +} + + + +struct TupleStruct(i32, i64, i16); + +// Change field value (tuple struct) ------------------------------------------- +#[cfg(cfail1)] +fn change_field_value_tuple_struct() -> TupleStruct { + TupleStruct(0, 1, 2) +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_field_value_tuple_struct() -> TupleStruct { + TupleStruct(0, 1, 3) +} + + + +struct TupleStruct2(u16, u16, u16); + +// Change constructor path (tuple struct) -------------------------------------- +#[cfg(cfail1)] +fn change_constructor_path_tuple_struct() { + let _ = TupleStruct(0, 1, 2); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_constructor_path_tuple_struct() { + let _ = TupleStruct2(0, 1, 2); +} + + + +// Change constructor path indirectly (tuple struct) --------------------------- +mod change_constructor_path_indirectly_tuple_struct { + #[cfg(cfail1)] + use super::TupleStruct as Struct; + #[cfg(not(cfail1))] + use super::TupleStruct2 as Struct; + + fn function() -> Struct { + Struct(0, 1, 2) + } +} diff --git a/src/test/run-pass/myriad-closures.rs b/src/test/run-pass-fulldeps/myriad-closures.rs similarity index 91% rename from src/test/run-pass/myriad-closures.rs rename to src/test/run-pass-fulldeps/myriad-closures.rs index d2c9a5d562b02..a946ec635b29f 100644 --- a/src/test/run-pass/myriad-closures.rs +++ b/src/test/run-pass-fulldeps/myriad-closures.rs @@ -13,6 +13,9 @@ // toolchain. // See https://github.com/rust-lang/rust/issues/34793 for more information. +// Make sure we don't optimize anything away: +// compile-flags: -C no-prepopulate-passes + // Expand something exponentially macro_rules! go_bacterial { ($mac:ident) => ($mac!()); @@ -23,10 +26,7 @@ macro_rules! go_bacterial { } macro_rules! mk_closure { - () => ({ - let c = |a: u32| a + 4; - let _ = c(2); - }) + () => ((move || {})()) } macro_rules! mk_fn { diff --git a/src/test/run-pass/issue-23699.rs b/src/test/run-pass/issue-23699.rs new file mode 100644 index 0000000000000..1909be4df7ba2 --- /dev/null +++ b/src/test/run-pass/issue-23699.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. + +fn gimme_a_raw_pointer(_: *const T) { } + +fn test(t: T) { } + +fn main() { + // Clearly `pointer` must be of type `*const ()`. + let pointer = &() as *const _; + gimme_a_raw_pointer(pointer); + + let t = test as fn (i32); + t(0i32); +} +