diff --git a/configure b/configure index 3d04cf7519ed4..652b0b477664f 100755 --- a/configure +++ b/configure @@ -323,6 +323,17 @@ envopt() { fi } +enable_if_not_disabled() { + local OP=$1 + local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') + local ENAB_V="CFG_ENABLE_$UOP" + local EXPLICITLY_DISABLED="CFG_DISABLE_${UOP}_PROVIDED" + eval VV=\$$EXPLICITLY_DISABLED + if [ -z "$VV" ]; then + eval $ENAB_V=1 + fi +} + to_llvm_triple() { case $1 in i686-w64-mingw32) echo i686-pc-windows-gnu ;; @@ -671,10 +682,12 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then CFG_DISABLE_OPTIMIZE=1 CFG_DISABLE_OPTIMIZE_CXX=1 fi - CFG_ENABLE_DEBUG_ASSERTIONS=1 - CFG_ENABLE_DEBUG_JEMALLOC=1 - CFG_ENABLE_DEBUGINFO=1 - CFG_ENABLE_LLVM_ASSERTIONS=1 + + # Set following variables to 1 unless setting already provided + enable_if_not_disabled debug-assertions + enable_if_not_disabled debug-jemalloc + enable_if_not_disabled debuginfo + enable_if_not_disabled llvm-assertions fi # OK, now write the debugging options diff --git a/mk/rt.mk b/mk/rt.mk index c70f9e8a37add..69277e774e43b 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -54,15 +54,6 @@ NATIVE_DEPS_miniz_$(1) = miniz.c NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \ rust_android_dummy.c NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S -ifeq ($$(findstring msvc,$(1)),msvc) -ifeq ($$(findstring i686,$(1)),i686) -NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll -else -NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll -endif -else -NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll -endif NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S @@ -76,14 +67,6 @@ NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S RT_OUTPUT_DIR_$(1) := $(1)/rt -$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \ - $$(LLVM_CONFIG_$$(CFG_BUILD)) - @mkdir -p $$(@D) - @$$(call E, compile: $$@) - $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \ - -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \ - -relocation-model=pic -o $$@ $$< - $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS) @mkdir -p $$(@D) @$$(call E, compile: $$@) @@ -122,7 +105,6 @@ define THIRD_PARTY_LIB OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o) -OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o) NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2)) $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1)) diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index cbedf86371414..753a5a32e8a1b 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -340,7 +340,7 @@ libraries: Note that frameworks are only available on OSX targets. The different `kind` values are meant to differentiate how the native library -participates in linkage. From a linkage perspective, the rust compiler creates +participates in linkage. From a linkage perspective, the Rust compiler creates two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary). Native dynamic library and framework dependencies are propagated to the final artifact boundary, while static library dependencies are not propagated at @@ -350,9 +350,9 @@ artifact. A few examples of how this model can be used are: * A native build dependency. Sometimes some C/C++ glue is needed when writing - some rust code, but distribution of the C/C++ code in a library format is just + some Rust code, but distribution of the C/C++ code in a library format is just a burden. In this case, the code will be archived into `libfoo.a` and then the - rust crate would declare a dependency via `#[link(name = "foo", kind = + Rust crate would declare a dependency via `#[link(name = "foo", kind = "static")]`. Regardless of the flavor of output for the crate, the native static library @@ -361,7 +361,7 @@ A few examples of how this model can be used are: * A normal dynamic dependency. Common system libraries (like `readline`) are available on a large number of systems, and often a static copy of these - libraries cannot be found. When this dependency is included in a rust crate, + libraries cannot be found. When this dependency is included in a Rust crate, partial targets (like rlibs) will not link to the library, but when the rlib is included in a final target (like a binary), the native library will be linked in. diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index 39e8ea6cbd319..83750ec3b01ad 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -2,7 +2,7 @@ The first step to using Rust is to install it! There are a number of ways to install Rust, but the easiest is to use the `rustup` script. If you're on Linux -or a Mac, all you need to do is this: +or a Mac, all you need to do is this: > Note: you don't need to type in the `$`s, they just indicate the start of > each command. You’ll see many tutorials and examples around the web that @@ -25,6 +25,12 @@ $ sh rustup.sh [insecurity]: http://curlpipesh.tumblr.com If you're on Windows, please download the appropriate [installer][install-page]. +**NOTE:** By default, the Windows installer will not add Rust to the %PATH% +system variable. If this is the only version of Rust you are installing and you +want to be able to run it from the command line, click on "Advanced" on the +install dialog and on the "Product Features" page ensure "Add to PATH" is +installed on the local hard drive. + [install-page]: http://www.rust-lang.org/install.html @@ -87,6 +93,11 @@ rustc 1.0.0 (a59de37e9 2015-05-13) If you did, Rust has been installed successfully! Congrats! +If you didn't and you're on Windows, check that Rust is in your %PATH% system +variable. If it isn't, run the installer again, select "Change" on the "Change, +repair, or remove installation" page and ensure "Add to PATH" is installed on +the local hard drive. + This installer also installs a copy of the documentation locally, so you can read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. On Windows, it's in a `share/doc` directory, inside wherever you installed Rust @@ -101,5 +112,5 @@ resources include [the user’s forum][users], and [irc]: irc://irc.mozilla.org/#rust [mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust -[users]: http://users.rust-lang.org/ +[users]: http://users.rust-lang.org/ [stackoverflow]: http://stackoverflow.com/questions/tagged/rust diff --git a/src/doc/trpl/release-channels.md b/src/doc/trpl/release-channels.md index 03e65539a2042..1e203c6553ee1 100644 --- a/src/doc/trpl/release-channels.md +++ b/src/doc/trpl/release-channels.md @@ -43,3 +43,26 @@ This will help alert the team in case there’s an accidental regression. Additionally, testing against nightly can catch regressions even sooner, and so if you don’t mind a third build, we’d appreciate testing against all channels. +As an example, many Rust programmers use [Travis](https://travis-ci.org/) to +test their crates, which is free for open source projects. Travis [supports +Rust directly][travis], and you can use a `.travis.yml` file like this to +test on all channels: + +```yaml +language: rust +rust: + - nightly + - beta + - stable + +matrix: + allow_failures: + - rust: nightly +``` + +[travis]: http://docs.travis-ci.com/user/languages/rust/ + +With this configuration, Travis will test all three channels, but if something +breaks on nightly, it won’t fail your build. A similar configuration is +recommended for any CI system, check the documentation of the one you’re +using for more details. diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 80b0c87473fa2..1b223365bd63a 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -100,10 +100,14 @@ that you normally can not do. Just three. Here they are: That’s it. It’s important that `unsafe` does not, for example, ‘turn off the borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its -semantics, it won’t just start accepting anything. +semantics, it won’t just start accepting anything. But it will let you write +things that _do_ break some of the rules. -But it will let you write things that _do_ break some of the rules. Let’s go -over these three abilities in order. +You will also encounter the `unsafe` keyword when writing bindings to foreign +(non-Rust) interfaces. You're encouraged to write a safe, native Rust interface +around the methods provided by the library. + +Let’s go over the basic three abilities listed, in order. ## Access or update a `static mut` diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5c1fd2a1aa1f4..ead0b4259a987 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -135,20 +135,3 @@ pub fn oom() -> ! { // allocate. unsafe { core::intrinsics::abort() } } - -// FIXME(#14344): When linking liballoc with libstd, this library will be linked -// as an rlib (it only exists as an rlib). It turns out that an -// optimized standard library doesn't actually use *any* symbols -// from this library. Everything is inlined and optimized away. -// This means that linkers will actually omit the object for this -// file, even though it may be needed in the future. -// -// To get around this for now, we define a dummy symbol which -// will never get inlined so the stdlib can call it. The stdlib's -// reference to this symbol will cause this library's object file -// to get linked in to libstd successfully (the linker won't -// optimize it out). -#[doc(hidden)] -#[unstable(feature = "issue_14344_fixme")] -#[cfg(stage0)] -pub fn fixme_14344_be_sure_to_link_to_collections() {} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index a2b2ae220f88e..1f94838499218 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -133,13 +133,6 @@ pub mod btree_set { pub use btree::set::*; } - -// FIXME(#14344) this shouldn't be necessary -#[doc(hidden)] -#[unstable(feature = "issue_14344_fixme")] -#[cfg(stage0)] -pub fn fixme_14344_be_sure_to_link_to_collections() {} - #[cfg(not(test))] mod std { pub use core::ops; // RangeFull diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index f5a27565ef7de..4378d0804df96 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Utilities for slice manipulation +//! A dynamically-sized view into a contiguous sequence, `[T]`. //! -//! The `slice` module contains useful code to help work with slice values. //! Slices are a view into a block of memory represented as a pointer and a //! length. //! @@ -78,7 +77,8 @@ //! iterators. //! * Further methods that return iterators are `.split()`, `.splitn()`, //! `.chunks()`, `.windows()` and more. -#![doc(primitive = "slice")] +//! +//! *[See also the slice primitive type](../primitive.slice.html).* #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index cb6613998b454..25a3441fd5bb6 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -8,43 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unicode string manipulation (the `str` type). +//! Unicode string slices //! -//! Rust's `str` type is one of the core primitive types of the language. `&str` -//! is the borrowed string type. This type of string can only be created from -//! other strings, unless it is a `&'static str` (see below). It is not possible -//! to move out of borrowed strings because they are owned elsewhere. -//! -//! # Examples -//! -//! Here's some code that uses a `&str`: -//! -//! ``` -//! let s = "Hello, world."; -//! ``` -//! -//! This `&str` is a `&'static str`, which is the type of string literals. -//! They're `'static` because literals are available for the entire lifetime of -//! the program. -//! -//! You can get a non-`'static` `&str` by taking a slice of a `String`: -//! -//! ``` -//! let some_string = "Hello, world.".to_string(); -//! let s = &some_string; -//! ``` -//! -//! # Representation -//! -//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as -//! a stream of UTF-8 bytes. All [strings](../../reference.html#literals) are -//! guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are -//! not null-terminated and can thus contain null bytes. -//! -//! The actual representation of `str`s have direct mappings to slices: `&str` -//! is the same as `&[u8]`. +//! *[See also the `str` primitive type](../primitive.str.html).* + -#![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index ebff4a9126daf..cc58952be600a 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -979,7 +979,6 @@ impl ops::Index for String { } } -#[cfg(not(stage0))] #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut> for String { #[inline] @@ -987,7 +986,6 @@ impl ops::IndexMut> for String { &mut self[..][index] } } -#[cfg(not(stage0))] #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut> for String { #[inline] @@ -995,7 +993,6 @@ impl ops::IndexMut> for String { &mut self[..][index] } } -#[cfg(not(stage0))] #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut> for String { #[inline] diff --git a/src/libcore/array.rs b/src/libcore/array.rs index a9b240de30bef..cfe22b8917874 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -11,8 +11,9 @@ //! Implementations of things like `Eq` for fixed-length arrays //! up to a certain length. Eventually we should able to generalize //! to all lengths. +//! +//! *[See also the array primitive type](../primitive.array.html).* -#![doc(primitive = "array")] #![unstable(feature = "fixed_size_array", reason = "traits and impls are better expressed through generic \ integer constants")] diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index a77df09664313..c6434e71957ae 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -78,6 +78,7 @@ use intrinsics; use cell::UnsafeCell; use default::Default; +use fmt; /// A boolean type which can be safely shared between threads. #[stable(feature = "rust1", since = "1.0.0")] @@ -1089,3 +1090,23 @@ pub fn fence(order: Ordering) { } } } + +macro_rules! impl_Debug { + ($($t:ident)*) => ($( + #[stable(feature = "atomic_debug", since = "1.3.0")] + impl fmt::Debug for $t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple(stringify!($t)).field(&self.load(Ordering::SeqCst)).finish() + } + } + )*); +} + +impl_Debug!{ AtomicUsize AtomicIsize AtomicBool } + +#[stable(feature = "atomic_debug", since = "1.3.0")] +impl fmt::Debug for AtomicPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish() + } +} diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 12aa06667a1dd..88aa805668cfa 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -13,7 +13,6 @@ //! For more details, see ::rustc_unicode::char (a.k.a. std::char) #![allow(non_snake_case)] -#![doc(primitive = "char")] #![stable(feature = "core_char", since = "1.2.0")] use iter::Iterator; diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index a098840c77a51..8141916dd60fc 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -12,8 +12,6 @@ // FIXME: #6220 Implement floating point formatting -#![allow(unsigned_negation)] - use prelude::*; use fmt; diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 74901553149ab..ef022179772c4 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -602,4 +602,10 @@ extern "rust-intrinsic" { /// Returns the value of the discriminant for the variant in 'v', /// cast to a `u64`; if `T` has no discriminant, returns 0. pub fn discriminant_value(v: &T) -> u64; + + /// Rust's "try catch" construct which invokes the function pointer `f` with + /// the data pointer `data`, returning the exception payload if an exception + /// is thrown (aka the thread panics). + #[cfg(not(stage0))] + pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8; } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 4c8511eb1902c..415326a8a616e 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2555,7 +2555,7 @@ impl RandomAccessIterator for Inspect #[unstable(feature = "iter_unfold")] #[derive(Clone)] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub struct Unfold { @@ -2567,7 +2567,7 @@ pub struct Unfold { #[unstable(feature = "iter_unfold")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] impl Unfold where F: FnMut(&mut St) -> Option { @@ -3018,7 +3018,7 @@ type IterateState = (F, Option, bool); /// from a given seed value. #[unstable(feature = "iter_iterate")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub type Iterate = Unfold, fn(&mut IterateState) -> Option>; @@ -3027,7 +3027,7 @@ pub type Iterate = Unfold, fn(&mut IterateState) /// repeated applications of the given function `f`. #[unstable(feature = "iter_iterate")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub fn iterate(seed: T, f: F) -> Iterate where diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 030d2a33f8f65..ef2a33c37dd30 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -154,10 +154,6 @@ pub mod str; pub mod hash; pub mod fmt; -#[doc(primitive = "bool")] -mod bool { -} - // note: does not need to be public mod tuple; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 9270d3f12b073..6b4424093b407 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,7 +10,6 @@ //! Operations and constants for 32-bits floats (`f32` type) -#![doc(primitive = "f32")] // FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353 #![allow(overflowing_literals)] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d2ab2695f5e5c..fa7aa2ab5ce8c 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,7 +10,6 @@ //! Operations and constants for 64-bits floats (`f64` type) -#![doc(primitive = "f64")] // FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353 #![allow(overflowing_literals)] diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 5ea60d0d96d29..dacb4ebcdfa3a 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 16-bits integers (`i16` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i16")] int_module! { i16, 16 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index 7d9faa998c12e..250d66de70b34 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 32-bits integers (`i32` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i32")] int_module! { i32, 32 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 5a70911387b9b..5ed21d7246cd0 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 64-bits integers (`i64` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i64")] int_module! { i64, 64 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index 1d7d78ffa6c23..0394c12d5c457 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 8-bits integers (`i8` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i8")] int_module! { i8, 8 } diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 2cdfe03eafe7f..066cb10cce265 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -11,7 +11,6 @@ //! Operations and constants for pointer-sized signed integers (`isize` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "isize")] #[cfg(target_pointer_width = "32")] int_module! { isize, 32 } diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index 21635799a77a2..ecf799448483c 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 16-bits integers (`u16` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u16")] uint_module! { u16, i16, 16 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index 7d520770503d4..b0682b55ac05d 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 32-bits integers (`u32` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u32")] uint_module! { u32, i32, 32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index f10822077dc75..dbc6a64a905d2 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 64-bits integer (`u64` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u64")] uint_module! { u64, i64, 64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 3d6922b07b194..bf9347ca62c92 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 8-bits integers (`u8` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u8")] uint_module! { u8, i8, 8 } diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 6fd23425e4d89..67e3c954ab695 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -11,6 +11,5 @@ //! Operations and constants for pointer-sized unsigned integers (`usize` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "usize")] uint_module! { usize, isize, ::isize::BITS } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 76d3c1df15998..c2a9b8c8308cd 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -517,7 +517,6 @@ pub trait Neg { macro_rules! neg_impl_core { ($id:ident => $body:expr, $($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[allow(unsigned_negation)] impl Neg for $t { #[stable(feature = "rust1", since = "1.0.0")] type Output = $t; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 7b33a41f9556a..13d95e9ab1a71 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,84 +10,11 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Operations on raw pointers, `*const T`, and `*mut T`. +//! Raw, unsafe pointers, `*const T`, and `*mut T` //! -//! Working with raw pointers in Rust is uncommon, -//! typically limited to a few patterns. -//! -//! Use the `null` function to create null pointers, and the `is_null` method -//! of the `*const T` type to check for null. The `*const T` type also defines -//! the `offset` method, for pointer math. -//! -//! # Common ways to create raw pointers -//! -//! ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). -//! -//! ``` -//! let my_num: i32 = 10; -//! let my_num_ptr: *const i32 = &my_num; -//! let mut my_speed: i32 = 88; -//! let my_speed_ptr: *mut i32 = &mut my_speed; -//! ``` -//! -//! To get a pointer to a boxed value, dereference the box: -//! -//! ``` -//! let my_num: Box = Box::new(10); -//! let my_num_ptr: *const i32 = &*my_num; -//! let mut my_speed: Box = Box::new(88); -//! let my_speed_ptr: *mut i32 = &mut *my_speed; -//! ``` -//! -//! This does not take ownership of the original allocation -//! and requires no resource management later, -//! but you must not use the pointer after its lifetime. -//! -//! ## 2. Consume a box (`Box`). -//! -//! The `into_raw` function consumes a box and returns -//! the raw pointer. It doesn't destroy `T` or deallocate any memory. -//! -//! ``` -//! # #![feature(box_raw)] -//! let my_speed: Box = Box::new(88); -//! let my_speed: *mut i32 = Box::into_raw(my_speed); -//! -//! // By taking ownership of the original `Box` though -//! // we are obligated to put it together later to be destroyed. -//! unsafe { -//! drop(Box::from_raw(my_speed)); -//! } -//! ``` -//! -//! Note that here the call to `drop` is for clarity - it indicates -//! that we are done with the given value and it should be destroyed. -//! -//! ## 3. Get it from C. -//! -//! ``` -//! # #![feature(libc)] -//! extern crate libc; -//! -//! use std::mem; -//! -//! fn main() { -//! unsafe { -//! let my_num: *mut i32 = libc::malloc(mem::size_of::() as libc::size_t) as *mut i32; -//! if my_num.is_null() { -//! panic!("failed to allocate memory"); -//! } -//! libc::free(my_num as *mut libc::c_void); -//! } -//! } -//! ``` -//! -//! Usually you wouldn't literally use `malloc` and `free` from Rust, -//! but C APIs hand out a lot of pointers generally, so are a common source -//! of raw pointers in Rust. +//! *[See also the pointer primitive types](../primitive.pointer.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "pointer")] use mem; use clone::Clone; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 2c6acbf9157de..9339f232e9197 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -13,7 +13,6 @@ //! For more details `std::slice`. #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "slice")] // How this module is organized. // diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e4c2ba3be875..5269cce174482 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -12,7 +12,6 @@ //! //! For more details, see std::str -#![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] use self::pattern::Pattern; @@ -636,10 +635,10 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split()`."] + /// Created with the method `.split()`. struct Split; reverse: - #[doc="Created with the method `.rsplit()`."] + /// Created with the method `.rsplit()`. struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -650,10 +649,10 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split_terminator()`."] + /// Created with the method `.split_terminator()`. struct SplitTerminator; reverse: - #[doc="Created with the method `.rsplit_terminator()`."] + /// Created with the method `.rsplit_terminator()`. struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -696,10 +695,10 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.splitn()`."] + /// Created with the method `.splitn()`. struct SplitN; reverse: - #[doc="Created with the method `.rsplitn()`."] + /// Created with the method `.rsplitn()`. struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -730,10 +729,10 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.match_indices()`."] + /// Created with the method `.match_indices()`. struct MatchIndices; reverse: - #[doc="Created with the method `.rmatch_indices()`."] + /// Created with the method `.rmatch_indices()`. struct RMatchIndices; stability: #[unstable(feature = "str_match_indices", @@ -771,10 +770,10 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.matches()`."] + /// Created with the method `.matches()`. struct Matches; reverse: - #[doc="Created with the method `.rmatches()`."] + /// Created with the method `.rmatches()`. struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index ba6a7c4a5fefa..6c5ff22232365 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations on tuples +//! A finite heterogeneous sequence, `(T, U, ..)` //! //! To access a single element of a tuple one can use the `.0` //! field access syntax. @@ -28,7 +28,6 @@ //! * `Default` #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "tuple")] use clone::Clone; use cmp::*; diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index cab2175f89781..247c3dcb9c705 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unsigned_negation)] - use core::fmt::radix; #[test] diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index dfcd08b69907a..c229df34ccf89 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -6535,8 +6535,4 @@ pub mod funcs { } } -#[doc(hidden)] -#[cfg(stage0)] -pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly - #[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index ec9aa2d16d24a..1b2210c89edcb 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -126,7 +126,6 @@ impl IsaacRng { /// Refills the output buffer (`self.rsl`) #[inline] - #[allow(unsigned_negation)] fn isaac(&mut self) { self.c = self.c + w(1); // abbreviations diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 4b77c211df983..4e21efcf9eb6b 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -335,6 +335,24 @@ This error indicates that an attempt was made to divide by zero (or take the remainder of a zero divisor) in a static or constant expression. "##, +E0030: r##" +When matching against a range, the compiler verifies that the range is +non-empty. Range patterns include both end-points, so this is equivalent to +requiring the start of the range to be less than or equal to the end of the +range. + +For example: + +``` +match 5u32 { + // This range is ok, albeit pointless. + 1 ... 1 => ... + // This range is empty, and the compiler can tell. + 1000 ... 5 => ... +} +``` +"##, + E0079: r##" Enum variants which contain no data can be given a custom integer representation. This error indicates that the value provided is not an diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 567be56b17f29..6d29a1031c6bc 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -75,6 +75,15 @@ enum TargetLint { /// Temporary renaming, used for easing migration pain; see #16545 Renamed(String, LintId), + + /// Lint with this name existed previously, but has been removed/deprecated. + /// The string argument is the reason for removal. + Removed(String), +} + +enum FindLintError { + NotFound, + Removed } impl LintStore { @@ -166,12 +175,16 @@ impl LintStore { self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target)); } + pub fn register_removed(&mut self, name: &str, reason: &str) { + self.by_name.insert(name.into(), Removed(reason.into())); + } + #[allow(unused_variables)] fn find_lint(&self, lint_name: &str, sess: &Session, span: Option) - -> Option + -> Result { match self.by_name.get(lint_name) { - Some(&Id(lint_id)) => Some(lint_id), + Some(&Id(lint_id)) => Ok(lint_id), Some(&Renamed(ref new_name, lint_id)) => { let warning = format!("lint {} has been renamed to {}", lint_name, new_name); @@ -179,17 +192,25 @@ impl LintStore { Some(span) => sess.span_warn(span, &warning[..]), None => sess.warn(&warning[..]), }; - Some(lint_id) - } - None => None + Ok(lint_id) + }, + Some(&Removed(ref reason)) => { + let warning = format!("lint {} has been removed: {}", lint_name, reason); + match span { + Some(span) => sess.span_warn(span, &warning[..]), + None => sess.warn(&warning[..]) + } + Err(FindLintError::Removed) + }, + None => Err(FindLintError::NotFound) } } pub fn process_command_line(&mut self, sess: &Session) { for &(ref lint_name, level) in &sess.opts.lint_opts { match self.find_lint(&lint_name[..], sess, None) { - Some(lint_id) => self.set_level(lint_id, (level, CommandLine)), - None => { + Ok(lint_id) => self.set_level(lint_id, (level, CommandLine)), + Err(_) => { match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone())) .collect::>>() @@ -398,8 +419,8 @@ impl<'a, 'tcx> Context<'a, 'tcx> { } Ok((lint_name, level, span)) => { match self.lints.find_lint(&lint_name, &self.tcx.sess, Some(span)) { - Some(lint_id) => vec![(lint_id, level, span)], - None => { + Ok(lint_id) => vec![(lint_id, level, span)], + Err(FindLintError::NotFound) => { match self.lints.lint_groups.get(&lint_name[..]) { Some(&(ref v, _)) => v.iter() .map(|lint_id: &LintId| @@ -412,7 +433,8 @@ impl<'a, 'tcx> Context<'a, 'tcx> { continue; } } - } + }, + Err(FindLintError::Removed) => { continue; } } } }; diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 59f91a50f7421..baaf6b6a0401d 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -26,6 +26,7 @@ use middle::cast::{CastKind}; use middle::const_eval; +use middle::const_eval::EvalHint::ExprTypeChecked; use middle::def; use middle::expr_use_visitor as euv; use middle::infer; @@ -39,6 +40,7 @@ use syntax::codemap::Span; use syntax::visit::{self, Visitor}; use std::collections::hash_map::Entry; +use std::cmp::Ordering; // Const qualification, from partial to completely promotable. bitflags! { @@ -365,6 +367,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { ast::PatRange(ref start, ref end) => { self.global_expr(Mode::Const, &**start); self.global_expr(Mode::Const, &**end); + + match const_eval::compare_lit_exprs(self.tcx, start, end) { + Some(Ordering::Less) | + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => { + span_err!(self.tcx.sess, start.span, E0030, + "lower range bound must be less than or equal to upper"); + } + None => { + self.tcx.sess.span_bug( + start.span, "literals of different types in range pat"); + } + } } _ => visit::walk_pat(self, p) } @@ -457,7 +472,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { match node_ty.sty { ty::TyUint(_) | ty::TyInt(_) if div_or_rem => { if !self.qualif.intersects(ConstQualif::NOT_CONST) { - match const_eval::eval_const_expr_partial(self.tcx, ex, None) { + match const_eval::eval_const_expr_partial( + self.tcx, ex, ExprTypeChecked) { Ok(_) => {} Err(msg) => { span_err!(self.tcx.sess, msg.span, E0020, diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index fc2444ed5b45c..d8c2341df2d9f 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -15,6 +15,7 @@ use self::WitnessPreference::*; use middle::const_eval::{compare_const_vals, ConstVal}; use middle::const_eval::{eval_const_expr, eval_const_expr_partial}; use middle::const_eval::{const_expr_to_pat, lookup_const_by_id}; +use middle::const_eval::EvalHint::ExprTypeChecked; use middle::def::*; use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init}; use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode}; @@ -263,7 +264,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { ast_util::walk_pat(pat, |p| { if let ast::PatLit(ref expr) = p.node { - match eval_const_expr_partial(cx.tcx, &**expr, None) { + match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) { Ok(ConstVal::Float(f)) if f.is_nan() => { span_warn!(cx.tcx.sess, p.span, E0003, "unmatchable NaN in pattern, \ diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 7d54b8c284f1f..9e2bcbaec8a6c 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -9,11 +9,10 @@ // except according to those terms. #![allow(non_camel_case_types)] -#![allow(unsigned_negation)] use self::ConstVal::*; - use self::ErrKind::*; +use self::EvalHint::*; use ast_map; use ast_map::blocks::FnLikeNode; @@ -27,7 +26,6 @@ use util::num::ToPrimitive; use syntax::ast::{self, Expr}; use syntax::ast_util; use syntax::codemap::Span; -use syntax::feature_gate; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::{codemap, visit}; @@ -273,6 +271,22 @@ pub enum ConstVal { Tuple(ast::NodeId), } +impl ConstVal { + pub fn description(&self) -> &'static str { + match *self { + Float(_) => "float", + Int(i) if i < 0 => "negative integer", + Int(_) => "positive integer", + Uint(_) => "unsigned integer", + Str(_) => "string literal", + Binary(_) => "binary array", + Bool(_) => "boolean", + Struct(_) => "struct", + Tuple(_) => "tuple", + } + } +} + pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P { let pat = match expr.node { ast::ExprTup(ref exprs) => @@ -331,7 +345,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P } pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal { - match eval_const_expr_partial(tcx, e, None) { + match eval_const_expr_partial(tcx, e, ExprTypeChecked) { Ok(r) => r, Err(s) => tcx.sess.span_fatal(s.span, &s.description()) } @@ -352,16 +366,8 @@ pub enum ErrKind { InvalidOpForFloats(ast::BinOp_), InvalidOpForIntUint(ast::BinOp_), InvalidOpForUintInt(ast::BinOp_), - NegateOnString, - NegateOnBoolean, - NegateOnBinary, - NegateOnStruct, - NegateOnTuple, - NotOnFloat, - NotOnString, - NotOnBinary, - NotOnStruct, - NotOnTuple, + NegateOn(ConstVal), + NotOn(ConstVal), NegateWithOverflow(i64), AddiWithOverflow(i64, i64), @@ -397,16 +403,8 @@ impl ConstEvalErr { InvalidOpForFloats(_) => "can't do this op on floats".into_cow(), InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(), InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(), - NegateOnString => "negate on string".into_cow(), - NegateOnBoolean => "negate on boolean".into_cow(), - NegateOnBinary => "negate on binary literal".into_cow(), - NegateOnStruct => "negate on struct".into_cow(), - NegateOnTuple => "negate on tuple".into_cow(), - NotOnFloat => "not on float or string".into_cow(), - NotOnString => "not on float or string".into_cow(), - NotOnBinary => "not on binary literal".into_cow(), - NotOnStruct => "not on struct".into_cow(), - NotOnTuple => "not on tuple".into_cow(), + NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(), + NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(), NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(), AddiWithOverflow(..) => "attempted to add with overflow".into_cow(), @@ -436,6 +434,28 @@ impl ConstEvalErr { pub type EvalResult = Result; pub type CastResult = Result; +// FIXME: Long-term, this enum should go away: trying to evaluate +// an expression which hasn't been type-checked is a recipe for +// disaster. That said, it's not clear how to fix ast_ty_to_ty +// to avoid the ordering issue. + +/// Hint to determine how to evaluate constant expressions which +/// might not be type-checked. +#[derive(Copy, Clone, Debug)] +pub enum EvalHint<'tcx> { + /// We have a type-checked expression. + ExprTypeChecked, + /// We have an expression which hasn't been type-checked, but we have + /// an idea of what the type will be because of the context. For example, + /// the length of an array is always `usize`. (This is referred to as + /// a hint because it isn't guaranteed to be consistent with what + /// type-checking would compute.) + UncheckedExprHint(Ty<'tcx>), + /// We have an expression which has not yet been type-checked, and + /// and we have no clue what the type will be. + UncheckedExprNoHint, +} + #[derive(Copy, Clone, PartialEq, Debug)] pub enum IntTy { I8, I16, I32, I64 } #[derive(Copy, Clone, PartialEq, Debug)] @@ -706,26 +726,34 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) { uint_shift_body overflowing_shr Uint ShiftRightWithOverflow }} -// After type checking, `eval_const_expr_partial` should always suffice. The -// reason for providing `eval_const_expr_with_substs` is to allow -// trait-associated consts to be evaluated *during* type checking, when the -// substs for each expression have not been written into `tcx` yet. +/// Evaluate a constant expression in a context where the expression isn't +/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked, +/// but a few places need to evaluate constants during type-checking, like +/// computing the length of an array. (See also the FIXME above EvalHint.) pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, e: &Expr, - ty_hint: Option>) -> EvalResult { - eval_const_expr_with_substs(tcx, e, ty_hint, |id| { - tcx.node_id_item_substs(id).substs - }) -} - -pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, - e: &Expr, - ty_hint: Option>, - get_substs: S) -> EvalResult - where S: Fn(ast::NodeId) -> subst::Substs<'tcx> { + ty_hint: EvalHint<'tcx>) -> EvalResult { fn fromb(b: bool) -> ConstVal { Int(b as i64) } - let ety = ty_hint.or_else(|| tcx.expr_ty_opt(e)); + // Try to compute the type of the expression based on the EvalHint. + // (See also the definition of EvalHint, and the FIXME above EvalHint.) + let ety = match ty_hint { + ExprTypeChecked => { + // After type-checking, expr_ty is guaranteed to succeed. + Some(tcx.expr_ty(e)) + } + UncheckedExprHint(ty) => { + // Use the type hint; it's not guaranteed to be right, but it's + // usually good enough. + Some(ty) + } + UncheckedExprNoHint => { + // This expression might not be type-checked, and we have no hint. + // Try to query the context for a type anyway; we might get lucky + // (for example, if the expression was imported from another crate). + tcx.expr_ty_opt(e) + } + }; // If type of expression itself is int or uint, normalize in these // bindings so that isize/usize is mapped to a type with an @@ -741,44 +769,35 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, let result = match e.node { ast::ExprUnary(ast::UnNeg, ref inner) => { - match try!(eval_const_expr_partial(tcx, &**inner, ety)) { + match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) { Float(f) => Float(-f), Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)), Uint(i) => { - if !tcx.sess.features.borrow().negate_unsigned { - feature_gate::emit_feature_err( - &tcx.sess.parse_sess.span_diagnostic, - "negate_unsigned", - e.span, - "unary negation of unsigned integers may be removed in the future"); - } try!(const_uint_checked_neg(i, e, expr_uint_type)) } - Str(_) => signal!(e, NegateOnString), - Bool(_) => signal!(e, NegateOnBoolean), - Binary(_) => signal!(e, NegateOnBinary), - Tuple(_) => signal!(e, NegateOnTuple), - Struct(..) => signal!(e, NegateOnStruct), + const_val => signal!(e, NegateOn(const_val)), } } ast::ExprUnary(ast::UnNot, ref inner) => { - match try!(eval_const_expr_partial(tcx, &**inner, ety)) { + match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) { Int(i) => Int(!i), Uint(i) => const_uint_not(i, expr_uint_type), Bool(b) => Bool(!b), - Str(_) => signal!(e, NotOnString), - Float(_) => signal!(e, NotOnFloat), - Binary(_) => signal!(e, NotOnBinary), - Tuple(_) => signal!(e, NotOnTuple), - Struct(..) => signal!(e, NotOnStruct), + const_val => signal!(e, NotOn(const_val)), } } ast::ExprBinary(op, ref a, ref b) => { let b_ty = match op.node { - ast::BiShl | ast::BiShr => Some(tcx.types.usize), - _ => ety + ast::BiShl | ast::BiShr => { + if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + UncheckedExprHint(tcx.types.usize) + } + } + _ => ty_hint }; - match (try!(eval_const_expr_partial(tcx, &**a, ety)), + match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)), try!(eval_const_expr_partial(tcx, &**b, b_ty))) { (Float(a), Float(b)) => { match op.node { @@ -868,22 +887,25 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, } } ast::ExprCast(ref base, ref target_ty) => { - // This tends to get called w/o the type actually having been - // populated in the ctxt, which was causing things to blow up - // (#5900). Fall back to doing a limited lookup to get past it. let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty)) .unwrap_or_else(|| { tcx.sess.span_fatal(target_ty.span, "target type not found for const cast") }); - // Prefer known type to noop, but always have a type hint. - // - // FIXME (#23833): the type-hint can cause problems, - // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result - // type to the sum, and thus no overflow is signaled. - let base_hint = tcx.expr_ty_opt(&**base).unwrap_or(ety); - let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint))); + let base_hint = if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + // FIXME (#23833): the type-hint can cause problems, + // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result + // type to the sum, and thus no overflow is signaled. + match tcx.expr_ty_opt(&base) { + Some(t) => UncheckedExprHint(t), + None => ty_hint + } + }; + + let val = try!(eval_const_expr_partial(tcx, &**base, base_hint)); match cast_const(tcx, val, ety) { Ok(val) => val, Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), @@ -913,12 +935,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, def::FromTrait(trait_id) => match tcx.map.find(def_id.node) { Some(ast_map::NodeTraitItem(ti)) => match ti.node { ast::ConstTraitItem(ref ty, _) => { - let substs = get_substs(e.id); - (resolve_trait_associated_const(tcx, - ti, - trait_id, - substs), - Some(&**ty)) + if let ExprTypeChecked = ty_hint { + let substs = tcx.node_id_item_substs(e.id).substs; + (resolve_trait_associated_const(tcx, + ti, + trait_id, + substs), + Some(&**ty)) + } else { + (None, None) + } } _ => (None, None) }, @@ -947,27 +973,42 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, Some(actual_e) => actual_e, None => signal!(e, NonConstPath) }; - let ety = ety.or_else(|| const_ty.and_then(|ty| ast_ty_to_prim_ty(tcx, ty))); - try!(eval_const_expr_partial(tcx, const_expr, ety)) + let item_hint = if let UncheckedExprNoHint = ty_hint { + match const_ty { + Some(ty) => match ast_ty_to_prim_ty(tcx, ty) { + Some(ty) => UncheckedExprHint(ty), + None => UncheckedExprNoHint + }, + None => UncheckedExprNoHint + } + } else { + ty_hint + }; + try!(eval_const_expr_partial(tcx, const_expr, item_hint)) } ast::ExprLit(ref lit) => { lit_to_const(&**lit, ety) } - ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ety)), + ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ty_hint)), ast::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)), + Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)), None => Int(0) } } ast::ExprTup(_) => Tuple(e.id), ast::ExprStruct(..) => Struct(e.id), ast::ExprTupField(ref base, index) => { - if let Ok(c) = eval_const_expr_partial(tcx, base, None) { + let base_hint = if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + UncheckedExprNoHint + }; + if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) { if let Tuple(tup_id) = c { if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node { if index.node < fields.len() { - return eval_const_expr_partial(tcx, &fields[index.node], None) + return eval_const_expr_partial(tcx, &fields[index.node], base_hint) } else { signal!(e, TupleIndexOutOfBounds); } @@ -983,13 +1024,18 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, } ast::ExprField(ref base, field_name) => { // Get the base expression if it is a struct and it is constant - if let Ok(c) = eval_const_expr_partial(tcx, base, None) { + let base_hint = if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + UncheckedExprNoHint + }; + if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) { if let Struct(struct_id) = c { if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node { // Check that the given field exists and evaluate it if let Some(f) = fields.iter().find(|f| f.ident.node.as_str() == field_name.node.as_str()) { - return eval_const_expr_partial(tcx, &*f.expr, None) + return eval_const_expr_partial(tcx, &*f.expr, base_hint) } else { signal!(e, MissingStructField); } @@ -1165,21 +1211,17 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option { }) } -pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>, - a: &Expr, - b: &Expr, - ty_hint: Option>, - get_substs: S) -> Option - where S: Fn(ast::NodeId) -> subst::Substs<'tcx> { - let a = match eval_const_expr_with_substs(tcx, a, ty_hint, - |id| {get_substs(id)}) { +pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, + a: &Expr, + b: &Expr) -> Option { + let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked) { Ok(a) => a, Err(e) => { tcx.sess.span_err(a.span, &e.description()); return None; } }; - let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) { + let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) { Ok(b) => b, Err(e) => { tcx.sess.span_err(b.span, &e.description()); diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index e08da94c7314a..d902cb07494e3 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -13,18 +13,21 @@ use middle::implicator::Implication; use middle::ty::{self, FreeRegion}; use util::common::can_reach; -use util::nodemap::FnvHashMap; +use util::nodemap::{FnvHashMap, FnvHashSet}; #[derive(Clone)] pub struct FreeRegionMap { - /// `free_region_map` maps from a free region `a` to a list of + /// `map` maps from a free region `a` to a list of /// free regions `bs` such that `a <= b for all b in bs` map: FnvHashMap>, + /// regions that are required to outlive (and therefore be + /// equal to) 'static. + statics: FnvHashSet } impl FreeRegionMap { pub fn new() -> FreeRegionMap { - FreeRegionMap { map: FnvHashMap() } + FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() } } pub fn relate_free_regions_from_implications<'tcx>(&mut self, @@ -59,6 +62,8 @@ impl FreeRegionMap { } ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { match (r_a, r_b) { + (ty::ReStatic, ty::ReFree(_)) => {}, + (ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a), (ty::ReFree(fr_a), ty::ReFree(fr_b)) => { // Record that `'a:'b`. Or, put another way, `'b <= 'a`. self.relate_free_regions(fr_b, fr_a); @@ -76,8 +81,12 @@ impl FreeRegionMap { } } - pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { - let mut sups = self.map.entry(sub).or_insert(Vec::new()); + fn relate_to_static(&mut self, sup: FreeRegion) { + self.statics.insert(sup); + } + + fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { + let mut sups = self.map.entry(sub).or_insert(Vec::new()); if !sups.contains(&sup) { sups.push(sup); } @@ -88,7 +97,7 @@ impl FreeRegionMap { /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub` /// (that is, the user can give two different names to the same lifetime). pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool { - can_reach(&self.map, sub, sup) + can_reach(&self.map, sub, sup) || self.is_static(&sup) } /// Determines whether one region is a subregion of another. This is intended to run *after @@ -116,10 +125,17 @@ impl FreeRegionMap { (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => self.sub_free_region(sub_fr, super_fr), + (ty::ReStatic, ty::ReFree(ref sup_fr)) => self.is_static(sup_fr), + _ => false, } } } -} + /// Determines whether this free-region is required to be 'static + pub fn is_static(&self, super_region: &ty::FreeRegion) -> bool { + debug!("is_static(super_region={:?})", super_region); + self.statics.iter().any(|s| can_reach(&self.map, *s, *super_region)) + } +} diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 4528abfb9294b..4b62c7beab002 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -869,7 +869,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // is the scope `s_id`. Otherwise, as we do not know // big the free region is precisely, the GLB is undefined. let fr_scope = fr.scope.to_code_extent(); - if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope { + if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope || + free_regions.is_static(fr) { Ok(s) } else { Err(TypeError::RegionsNoOverlap(b, a)) diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index c5f6f0126de37..a10e0b8dfc29e 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { if from_tc.interior_param() || to_tc.interior_param() { span_err!(self.tcx.sess, span, E0139, "cannot transmute to or from a type that contains \ - type parameters in its interior"); + unsubstituted type parameters"); return; } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index cf528e0c8a914..f7cd94f30af12 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -326,6 +326,8 @@ lets_do_this! { StartFnLangItem, "start", start_fn; EhPersonalityLangItem, "eh_personality", eh_personality; + EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch; + MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter; ExchangeHeapLangItem, "exchange_heap", exchange_heap; OwnedBoxLangItem, "owned_box", owned_box; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 9e5ad7b42f5c5..510f1a2a2c9d8 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -372,6 +372,12 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v ast::Block) { impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { fn visit_expr(&mut self, ex: &'v ast::Expr) { + // do not recurse into closures defined in the block + // since they are treated as separate fns from the POV of + // labels_in_fn + if let ast::ExprClosure(..) = ex.node { + return + } if let Some(label) = expression_label(ex) { for &(prior, prior_span) in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ef337b4163051..17a76f6eed9c5 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -45,6 +45,7 @@ use middle; use middle::cast; use middle::check_const; use middle::const_eval::{self, ConstVal}; +use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def::{self, DefMap, ExportMap}; use middle::dependency_format; use middle::fast_reject; @@ -5758,20 +5759,8 @@ impl<'tcx> ctxt<'tcx> { Some(ref e) => { debug!("disr expr, checking {}", pprust::expr_to_string(&**e)); - // check_expr (from check_const pass) doesn't guarantee - // that the expression is in a form that eval_const_expr can - // handle, so we may still get an internal compiler error - // - // pnkfelix: The above comment was transcribed from - // the version of this code taken from rustc_typeck. - // Presumably the implication is that we need to deal - // with such ICE's as they arise. - // - // Since this can be called from `ty::enum_variants` - // anyway, best thing is to make `eval_const_expr` - // more robust (on case-by-case basis). - - match const_eval::eval_const_expr_partial(self, &**e, Some(repr_type_ty)) { + let hint = UncheckedExprHint(repr_type_ty); + match const_eval::eval_const_expr_partial(self, &**e, hint) { Ok(ConstVal::Int(val)) => current_disr_val = val as Disr, Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr, Ok(_) => { @@ -6086,18 +6075,13 @@ impl<'tcx> ctxt<'tcx> { // Returns the repeat count for a repeating vector expression. pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize { - match const_eval::eval_const_expr_partial(self, count_expr, Some(self.types.usize)) { + let hint = UncheckedExprHint(self.types.usize); + match const_eval::eval_const_expr_partial(self, count_expr, hint) { Ok(val) => { let found = match val { ConstVal::Uint(count) => return count as usize, ConstVal::Int(count) if count >= 0 => return count as usize, - ConstVal::Int(_) => "negative integer", - ConstVal::Float(_) => "float", - ConstVal::Str(_) => "string", - ConstVal::Bool(_) => "boolean", - ConstVal::Binary(_) => "binary array", - ConstVal::Struct(..) => "struct", - ConstVal::Tuple(_) => "tuple" + const_val => const_val.description(), }; span_err!(self.sess, count_expr.span, E0306, "expected positive integer for repeat count, found {}", diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 60a9ffc7d2e13..72fda9a7ae06a 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -119,7 +119,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { ) } weak_lang_items! { - panic_fmt, PanicFmtLangItem, rust_begin_unwind; + panic_fmt, PanicFmtLangItem, rust_begin_unwind; stack_exhausted, StackExhaustedLangItem, rust_stack_exhausted; eh_personality, EhPersonalityLangItem, rust_eh_personality; } diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 9b20bd927cb7a..4d3f9668c9f6b 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -27,7 +27,7 @@ pub fn opts() -> TargetOptions { "-Wl,--as-needed".to_string(), ), position_independent_executables: true, - archive_format: "bsd".to_string(), + archive_format: "gnu".to_string(), .. Default::default() } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1574080b313b5..ae95466e6e675 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -39,6 +39,7 @@ use middle::ty::{self, Ty}; use middle::traits; use middle::{def, pat_util, stability}; use middle::const_eval::{eval_const_expr_partial, ConstVal}; +use middle::const_eval::EvalHint::ExprTypeChecked; use middle::cfg; use rustc::ast_map; use util::nodemap::{FnvHashMap, NodeSet}; @@ -88,12 +89,6 @@ impl LintPass for WhileTrue { } } -declare_lint! { - UNSIGNED_NEGATION, - Warn, - "using an unary minus operator on unsigned type" -} - declare_lint! { UNUSED_COMPARISONS, Warn, @@ -128,8 +123,7 @@ impl TypeLimits { impl LintPass for TypeLimits { fn get_lints(&self) -> LintArray { - lint_array!(UNSIGNED_NEGATION, UNUSED_COMPARISONS, OVERFLOWING_LITERALS, - EXCEEDING_BITSHIFTS) + lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS) } fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { @@ -139,9 +133,12 @@ impl LintPass for TypeLimits { ast::ExprLit(ref lit) => { match lit.node { ast::LitInt(_, ast::UnsignedIntLit(_)) => { - cx.span_lint(UNSIGNED_NEGATION, e.span, - "negation of unsigned int literal may \ - be unintentional"); + check_unsigned_negation_feature(cx, e.span); + }, + ast::LitInt(_, ast::UnsuffixedIntLit(_)) => { + if let ty::TyUint(_) = cx.tcx.expr_ty(e).sty { + check_unsigned_negation_feature(cx, e.span); + } }, _ => () } @@ -150,9 +147,7 @@ impl LintPass for TypeLimits { let t = cx.tcx.expr_ty(&**expr); match t.sty { ty::TyUint(_) => { - cx.span_lint(UNSIGNED_NEGATION, e.span, - "negation of unsigned int variable may \ - be unintentional"); + check_unsigned_negation_feature(cx, e.span); }, _ => () } @@ -184,7 +179,7 @@ impl LintPass for TypeLimits { if let ast::LitInt(shift, _) = lit.node { shift >= bits } else { false } } else { - match eval_const_expr_partial(cx.tcx, &**r, Some(cx.tcx.types.usize)) { + match eval_const_expr_partial(cx.tcx, &**r, ExprTypeChecked) { Ok(ConstVal::Int(shift)) => { shift as u64 >= bits }, Ok(ConstVal::Uint(shift)) => { shift >= bits }, _ => { false } @@ -385,6 +380,18 @@ impl LintPass for TypeLimits { _ => false } } + + fn check_unsigned_negation_feature(cx: &Context, span: Span) { + if !cx.sess().features.borrow().negate_unsigned { + // FIXME(#27141): change this to syntax::feature_gate::emit_feature_err… + cx.sess().span_warn(span, + "unary negation of unsigned integers will be feature gated in the future"); + // …and remove following two expressions. + if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; } + cx.sess().fileline_help(span, "add #![feature(negate_unsigned)] to the \ + crate attributes to enable the gate in advance"); + } + } } } @@ -1610,8 +1617,6 @@ impl LintPass for MissingDoc { } return }, - ast::ItemConst(..) => "a constant", - ast::ItemStatic(..) => "a static", _ => return }; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c680906dd135b..54c1a79e10a9b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -134,4 +134,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_renamed("raw_pointer_deriving", "raw_pointer_derive"); store.register_renamed("unknown_features", "unused_features"); + + store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 7734704b021a8..83f8619c5eeab 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -134,7 +134,7 @@ pub enum DLLStorageClassTypes { } bitflags! { - flags Attribute : u32 { + flags Attribute : u64 { const ZExt = 1 << 0, const SExt = 1 << 1, const NoReturn = 1 << 2, @@ -161,6 +161,7 @@ bitflags! { const ReturnsTwice = 1 << 29, const UWTable = 1 << 30, const NonLazyBind = 1 << 31, + const OptimizeNone = 1 << 42, } } @@ -2193,7 +2194,8 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) { unsafe { - LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr.bits() as uint64_t) + LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, + attr.bits() as uint64_t) } } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a0d06e5e1244a..5a941c757fc6d 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -106,8 +106,7 @@ mod foo { use foo::MyTrait::do_something; ``` -In general, it's not legal to directly import methods belonging to a -trait or concrete type. +It's illegal to directly import methods belonging to a trait or concrete type. "##, E0255: r##" @@ -272,7 +271,160 @@ See the 'Use Declarations' section of the reference for more information on this topic: http://doc.rust-lang.org/reference.html#use-declarations -"## +"##, + +E0403: r##" +Some type parameters have the same name. Example of erroneous code: + +``` +fn foo(s: T, u: T) {} // error: the name `T` is already used for a type + // parameter in this type parameter list +``` + +Please verify that none of the type parameterss are misspelled, and rename any +clashing parameters. Example: + +``` +fn foo(s: T, u: Y) {} // ok! +``` +"##, + +E0404: r##" +You tried to implement something which was not a trait on an object. Example of +erroneous code: + +``` +struct Foo; +struct Bar; + +impl Foo for Bar {} // error: `Foo` is not a trait +``` + +Please verify that you didn't misspell the trait's name or otherwise use the +wrong identifier. Example: + +``` +trait Foo { + // some functions +} +struct Bar; + +impl Foo for Bar { // ok! + // functions implementation +} +``` +"##, + +E0405: r##" +An unknown trait was implemented. Example of erroneous code: + +``` +struct Foo; + +impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait` +``` + +Please verify that the name of the trait wasn't misspelled and ensure that it +was imported. Example: + +``` +// solution 1: +use some_file::SomeTrait; + +// solution 2: +trait SomeTrait { + // some functions +} + +struct Foo; + +impl SomeTrait for Foo { // ok! + // implements functions +} +``` +"##, + +E0407: r##" +A definition of a method not in the implemented trait was given in a trait +implementation. Example of erroneous code: + +``` +trait Foo { + fn a(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} + fn b() {} // error: method `b` is not a member of trait `Foo` +} +``` + +Please verify you didn't misspell the method name and you used the correct +trait. First example: + +``` +trait Foo { + fn a(); + fn b(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} + fn b() {} // ok! +} +``` + +Second example: + +``` +trait Foo { + fn a(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} +} + +impl Bar { + fn b() {} +} +``` +"##, + +E0428: r##" +A type or module has been defined more than once. Example of erroneous +code: + +``` +struct Bar; +struct Bar; // error: duplicate definition of value `Bar` +``` + +Please verify you didn't misspell the type/module's name or remove/rename the +duplicated one. Example: + +``` +struct Bar; +struct Bar2; // ok! +``` +"##, + +E0433: r##" +Invalid import. Example of erroneous code: + +``` +use something_which_doesnt_exist; +// error: unresolved import `something_which_doesnt_exist` +``` + +Please verify you didn't misspell the import's name. +"##, } @@ -284,11 +436,7 @@ register_diagnostics! { E0258, E0401, // can't use type parameters from outer function E0402, // cannot use an outer type parameter in this context - E0403, // the name `{}` is already used - E0404, // is not a trait - E0405, // use of undeclared trait name E0406, // undeclared associated type - E0407, // method is not a member of trait E0408, // variable from pattern #1 is not bound in pattern # E0409, // variable is bound with different mode in pattern # than in // pattern #1 @@ -313,13 +461,11 @@ register_diagnostics! { E0425, // unresolved name E0426, // use of undeclared label E0427, // cannot use `ref` binding mode with ... - E0428, // duplicate definition of ... E0429, // `self` imports are only allowed within a { } list E0430, // `self` import can only appear once in the list E0431, // `self` import can only appear in an import list with a non-empty // prefix 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 E0437, // type is not a member of trait diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 9a9b9c617a853..925da81d77e6b 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -235,8 +235,7 @@ struct ConstantExpr<'a>(&'a ast::Expr); impl<'a> ConstantExpr<'a> { fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool { - match const_eval::compare_lit_exprs(tcx, self.0, other.0, None, - |id| {tcx.node_id_item_substs(id).substs}) { + match const_eval::compare_lit_exprs(tcx, self.0, other.0) { Some(result) => result == Ordering::Equal, None => panic!("compare_list_exprs: type mismatch"), } diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 2b480abe3f1f3..7b2bdee50fe78 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -41,8 +41,6 @@ //! used unboxed and any field can have pointers (including mutable) //! taken to it, implementing them for Rust seems difficult. -#![allow(unsigned_negation)] - pub use self::Repr::*; use std::rc::Rc; diff --git a/src/librustc_trans/trans/build.rs b/src/librustc_trans/trans/build.rs index 3e4452a23b9f7..5a3fcc8d27f3c 100644 --- a/src/librustc_trans/trans/build.rs +++ b/src/librustc_trans/trans/build.rs @@ -1042,6 +1042,10 @@ pub fn LandingPad(cx: Block, ty: Type, pers_fn: ValueRef, B(cx).landing_pad(ty, pers_fn, num_clauses, cx.fcx.llfn) } +pub fn AddClause(cx: Block, landing_pad: ValueRef, clause: ValueRef) { + B(cx).add_clause(landing_pad, clause) +} + pub fn SetCleanup(cx: Block, landing_pad: ValueRef) { B(cx).set_cleanup(landing_pad) } diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index e39fc18dc7bf1..107ae378ac446 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -937,6 +937,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) { + unsafe { + llvm::LLVMAddClause(landing_pad, clause); + } + } + pub fn set_cleanup(&self, landing_pad: ValueRef) { self.count_insn("setcleanup"); unsafe { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index debc8dd59c04c..7900000d3a9df 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -620,16 +620,17 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }, ArgVals(args), dest) } -/// This behemoth of a function translates function calls. Unfortunately, in order to generate more -/// efficient LLVM output at -O0, it has quite a complex signature (refactoring this into two -/// functions seems like a good idea). +/// This behemoth of a function translates function calls. Unfortunately, in +/// order to generate more efficient LLVM output at -O0, it has quite a complex +/// signature (refactoring this into two functions seems like a good idea). /// -/// In particular, for lang items, it is invoked with a dest of None, and in that case the return -/// value contains the result of the fn. The lang item must not return a structural type or else -/// all heck breaks loose. +/// In particular, for lang items, it is invoked with a dest of None, and in +/// that case the return value contains the result of the fn. The lang item must +/// not return a structural type or else all heck breaks loose. /// -/// For non-lang items, `dest` is always Some, and hence the result is written into memory -/// somewhere. Nonetheless we return the actual return value of the function. +/// For non-lang items, `dest` is always Some, and hence the result is written +/// into memory somewhere. Nonetheless we return the actual return value of the +/// function. pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc, get_callee: F, diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 1891320313a85..37722d5a549fe 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -122,11 +122,9 @@ pub use self::Heap::*; use llvm::{BasicBlockRef, ValueRef}; use trans::base; use trans::build; -use trans::callee; use trans::common; -use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan}; +use trans::common::{Block, FunctionContext, NodeIdAndSpan}; use trans::debuginfo::{DebugLoc, ToDebugLoc}; -use trans::declare; use trans::glue; use middle::region; use trans::type_::Type; @@ -833,53 +831,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx &[Type::i8p(self.ccx), Type::i32(self.ccx)], false); - // The exception handling personality function. - // - // If our compilation unit has the `eh_personality` lang item somewhere - // within it, then we just need to translate that. Otherwise, we're - // building an rlib which will depend on some upstream implementation of - // this function, so we just codegen a generic reference to it. We don't - // specify any of the types for the function, we just make it a symbol - // that LLVM can later use. - // - // Note that MSVC is a little special here in that we don't use the - // `eh_personality` lang item at all. Currently LLVM has support for - // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the - // *name of the personality function* to decide what kind of unwind side - // tables/landing pads to emit. It looks like Dwarf is used by default, - // injecting a dependency on the `_Unwind_Resume` symbol for resuming - // an "exception", but for MSVC we want to force SEH. This means that we - // can't actually have the personality function be our standard - // `rust_eh_personality` function, but rather we wired it up to the - // CRT's custom personality function, which forces LLVM to consider - // landing pads as "landing pads for SEH". - let target = &self.ccx.sess().target.target; - let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { - Some(def_id) if !target.options.is_like_msvc => { - callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0), - pad_bcx.fcx.param_substs).val - } - _ => { - let mut personality = self.ccx.eh_personality().borrow_mut(); - match *personality { - Some(llpersonality) => llpersonality, - None => { - let name = if !target.options.is_like_msvc { - "rust_eh_personality" - } else if target.arch == "x86" { - "_except_handler3" - } else { - "__C_specific_handler" - }; - let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = declare::declare_cfn(self.ccx, name, fty, - self.ccx.tcx().types.i32); - *personality = Some(f); - f - } - } - } - }; + let llpersonality = pad_bcx.fcx.eh_personality(); // The only landing pad clause will be 'cleanup' let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index d813e9dbf40fa..f00029ec2ff93 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -163,11 +163,10 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc mangle_internal_name_by_path_and_seq(path, "closure") }); - // Currently there’s only a single user of get_or_create_declaration_if_closure and it - // unconditionally defines the function, therefore we use define_* here. - let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", symbol)); - }); + // Currently there’s only a single user of + // get_or_create_declaration_if_closure and it unconditionally defines the + // function, therefore we use define_* here. + let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type); // set an inline hint for all closures attributes::inline(llfn, attributes::InlineAttr::Hint); @@ -388,11 +387,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); - let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty) - .unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); - }); - + let lloncefn = declare::define_internal_rust_fn(ccx, &function_name, + llonce_fn_ty); let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d7d3be699cb90..8ec65639b5227 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -25,6 +25,7 @@ use middle::lang_items::LangItem; use middle::subst::{self, Substs}; use trans::base; use trans::build; +use trans::callee; use trans::cleanup; use trans::consts; use trans::datum; @@ -479,6 +480,56 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env) } + + pub fn eh_personality(&self) -> ValueRef { + // The exception handling personality function. + // + // If our compilation unit has the `eh_personality` lang item somewhere + // within it, then we just need to translate that. Otherwise, we're + // building an rlib which will depend on some upstream implementation of + // this function, so we just codegen a generic reference to it. We don't + // specify any of the types for the function, we just make it a symbol + // that LLVM can later use. + // + // Note that MSVC is a little special here in that we don't use the + // `eh_personality` lang item at all. Currently LLVM has support for + // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the + // *name of the personality function* to decide what kind of unwind side + // tables/landing pads to emit. It looks like Dwarf is used by default, + // injecting a dependency on the `_Unwind_Resume` symbol for resuming + // an "exception", but for MSVC we want to force SEH. This means that we + // can't actually have the personality function be our standard + // `rust_eh_personality` function, but rather we wired it up to the + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". + let target = &self.ccx.sess().target.target; + match self.ccx.tcx().lang_items.eh_personality() { + Some(def_id) if !target.options.is_like_msvc => { + callee::trans_fn_ref(self.ccx, def_id, ExprId(0), + self.param_substs).val + } + _ => { + let mut personality = self.ccx.eh_personality().borrow_mut(); + match *personality { + Some(llpersonality) => llpersonality, + None => { + let name = if !target.options.is_like_msvc { + "rust_eh_personality" + } else if target.arch == "x86" { + "_except_handler3" + } else { + "__C_specific_handler" + }; + let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); + let f = declare::declare_cfn(self.ccx, name, fty, + self.ccx.tcx().types.i32); + *personality = Some(f); + f + } + } + } + } + } } // Basic block context. We create a block context for each basic block @@ -905,11 +956,13 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let vtable = selection.map(|predicate| { fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable); + let vtable = erase_regions(tcx, + &drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable) + ); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - info!("Cache miss: {:?}", trait_ref); - ccx.trait_cache().borrow_mut().insert(trait_ref, - vtable.clone()); + ccx.trait_cache().borrow_mut().insert(trait_ref, vtable.clone()); vtable } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 242eceb8335b2..302ef68bddc7d 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -23,6 +23,8 @@ use middle::const_eval::{const_int_checked_div, const_uint_checked_div}; use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem}; use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl}; use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr}; +use middle::const_eval::EvalHint::ExprTypeChecked; +use middle::const_eval::eval_const_expr_partial; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; use trans::common::*; @@ -591,7 +593,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ast::ExprIndex(ref base, ref index) => { let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); - let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) { + let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) { Ok(ConstVal::Int(i)) => i as u64, Ok(ConstVal::Uint(u)) => u, _ => cx.sess().span_bug(index.span, diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 5a4bd7ff3a184..760a4ae827aac 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -142,6 +142,7 @@ pub struct LocalCrateContext<'tcx> { dbg_cx: Option>, eh_personality: RefCell>, + rust_try_fn: RefCell>, intrinsics: RefCell>, @@ -461,6 +462,7 @@ impl<'tcx> LocalCrateContext<'tcx> { closure_vals: RefCell::new(FnvHashMap()), dbg_cx: dbg_cx, eh_personality: RefCell::new(None), + rust_try_fn: RefCell::new(None), intrinsics: RefCell::new(FnvHashMap()), n_llvm_insns: Cell::new(0), trait_cache: RefCell::new(FnvHashMap()), @@ -726,6 +728,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.eh_personality } + pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell> { + &self.local.rust_try_fn + } + fn intrinsics<'a>(&'a self) -> &'a RefCell> { &self.local.intrinsics } @@ -923,6 +929,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option void); ifn!("llvm.expect.i1", fn(i1, i1) -> i1); + ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); // Some intrinsics were introduced in later versions of LLVM, but they have // fallbacks in libc or libm and such. diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 599a255ef8b6c..5f17197a4b9a7 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -796,12 +796,31 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ty::TyBareFn(_, ref barefnty) => { - subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span) + let fn_metadata = subroutine_type_metadata(cx, + unique_type_id, + &barefnty.sig, + usage_site_span).metadata; + match debug_context(cx).type_map + .borrow() + .find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => return metadata, + None => { /* proceed normally */ } + }; + + // This is actually a function pointer, so wrap it in pointer DI + MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) + } ty::TyClosure(def_id, substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); - let sig = infcx.closure_type(def_id, substs).sig; - subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); + let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); + + prepare_tuple_metadata(cx, + t, + &upvar_types[..], + unique_type_id, + usage_site_span).finalize(cx) } ty::TyStruct(def_id, substs) => { prepare_struct_metadata(cx, @@ -920,7 +939,7 @@ pub fn scope_metadata(fcx: &FunctionContext, } } -fn diverging_type_metadata(cx: &CrateContext) -> DIType { +pub fn diverging_type_metadata(cx: &CrateContext) -> DIType { unsafe { llvm::LLVMDIBuilderCreateBasicType( DIB(cx), diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index a873529891731..9ce5c457bff33 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -18,7 +18,8 @@ use self::utils::{DIB, span_start, assert_type_for_node_id, contains_nodebug_att create_DIArray, is_node_local_to_unit}; use self::namespace::{namespace_for_item, NamespaceTreeNode}; use self::type_names::compute_debuginfo_type_name; -use self::metadata::{type_metadata, file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; +use self::metadata::{type_metadata, diverging_type_metadata}; +use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; use self::source_loc::InternalDebugLocation; use llvm; @@ -29,8 +30,8 @@ use middle::subst::{self, Substs}; use rustc::ast_map; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; -use trans::monomorphize; -use middle::ty::Ty; +use trans::{monomorphize, type_of}; +use middle::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; @@ -40,7 +41,7 @@ use std::ffi::CString; use std::ptr; use std::rc::Rc; use syntax::codemap::{Span, Pos}; -use syntax::{ast, codemap, ast_util}; +use syntax::{abi, ast, codemap, ast_util}; use syntax::attr::IntType; use syntax::parse::token::{self, special_idents}; @@ -325,7 +326,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let function_type_metadata = unsafe { let fn_signature = get_function_signature(cx, fn_ast_id, - &*fn_decl, param_substs, span); llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) @@ -402,35 +402,49 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn_ast_id: ast::NodeId, - fn_decl: &ast::FnDecl, param_substs: &Substs<'tcx>, error_reporting_span: Span) -> DIArray { if cx.sess().opts.debuginfo == LimitedDebugInfo { return create_DIArray(DIB(cx), &[]); } - let mut signature = Vec::with_capacity(fn_decl.inputs.len() + 1); - // Return type -- llvm::DIBuilder wants this at index 0 assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); - let return_type = cx.tcx().node_id_to_type(fn_ast_id); - let return_type = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &return_type); - if return_type.is_nil() { - signature.push(ptr::null_mut()) + let fn_type = cx.tcx().node_id_to_type(fn_ast_id); + + let (sig, abi) = match fn_type.sty { + ty::TyBareFn(_, ref barefnty) => { + (cx.tcx().erase_late_bound_regions(&barefnty.sig), barefnty.abi) + } + ty::TyClosure(def_id, substs) => { + let closure_type = cx.tcx().closure_type(def_id, substs); + (cx.tcx().erase_late_bound_regions(&closure_type.sig), closure_type.abi) + } + + _ => cx.sess().bug("get_function_metdata: Expected a function type!") + }; + let sig = monomorphize::apply_param_substs(cx.tcx(), param_substs, &sig); + + let mut signature = Vec::with_capacity(sig.inputs.len() + 1); + + // Return type -- llvm::DIBuilder wants this at index 0 + signature.push(match sig.output { + ty::FnConverging(ret_ty) => match ret_ty.sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, ret_ty, codemap::DUMMY_SP) + }, + ty::FnDiverging => diverging_type_metadata(cx) + }); + + let inputs = &if abi == abi::RustCall { + type_of::untuple_arguments(cx, &sig.inputs) } else { - signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP)); - } + sig.inputs + }; // Arguments types - for arg in &fn_decl.inputs { - assert_type_for_node_id(cx, arg.pat.id, arg.pat.span); - let arg_type = cx.tcx().node_id_to_type(arg.pat.id); - let arg_type = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &arg_type); - signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP)); + for &argument_type in inputs { + signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP)); } return create_DIArray(DIB(cx), &signature[..]); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index b29da9d560fea..c802de91e38b3 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -176,8 +176,8 @@ pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option Option { +pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, + fn_type: Type, output: ty::FnOutput) -> Option { if get_defined_value(ccx, name).is_some() { None } else { @@ -224,20 +224,21 @@ pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, /// Declare a Rust function with an intention to define it. /// /// Use this function when you intend to define a function. This function will -/// return None if the name already has a definition associated with it. In that -/// case an error should be reported to the user, because it usually happens due -/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes). -pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, - fn_type: ty::Ty<'tcx>) -> Option { +/// return panic if the name already has a definition associated with it. This +/// can happen with #[no_mangle] or #[export_name], for example. +pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { if get_defined_value(ccx, name).is_some() { - None + ccx.sess().fatal(&format!("symbol `{}` already defined", name)) } else { - Some(declare_internal_rust_fn(ccx, name, fn_type)) + declare_internal_rust_fn(ccx, name, fn_type) } } -/// Get defined or externally defined (AvailableExternally linkage) value by name. +/// Get defined or externally defined (AvailableExternally linkage) value by +/// name. fn get_defined_value(ccx: &CrateContext, name: &str) -> Option { debug!("get_defined_value(name={:?})", name); let namebuf = CString::new(name).unwrap_or_else(|_|{ diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 9e8c0189a9762..e102e3cd062be 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -627,9 +627,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.tcx().map.path_to_string(id), id, t); - let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", ps)); - }); + let llfn = declare::define_internal_rust_fn(ccx, &ps, t); attributes::from_fn_attrs(ccx, attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index b449c3ad060b8..e78218fd10dd8 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -10,6 +10,7 @@ #![allow(non_upper_case_globals)] +use arena::TypedArena; use llvm; use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; use middle::subst; @@ -23,6 +24,7 @@ use trans::cleanup::CleanupMethods; use trans::common::*; use trans::datum::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr; use trans::glue; use trans::type_of::*; @@ -31,7 +33,8 @@ use trans::machine; use trans::machine::llsize_of; use trans::type_::Type; use middle::ty::{self, Ty, HasTypeFlags}; -use syntax::abi::RustIntrinsic; +use middle::subst::Substs; +use syntax::abi::{self, RustIntrinsic}; use syntax::ast; use syntax::parse::token; @@ -302,6 +305,42 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } + let call_debug_location = DebugLoc::At(call_info.id, call_info.span); + + // For `try` we need some custom control flow + if &name[..] == "try" { + if let callee::ArgExprs(ref exprs) = args { + let (func, data) = if exprs.len() != 2 { + ccx.sess().bug("expected two exprs as arguments for \ + `try` intrinsic"); + } else { + (&exprs[0], &exprs[1]) + }; + + // translate arguments + let func = unpack_datum!(bcx, expr::trans(bcx, func)); + let func = unpack_datum!(bcx, func.to_rvalue_datum(bcx, "func")); + let data = unpack_datum!(bcx, expr::trans(bcx, data)); + let data = unpack_datum!(bcx, data.to_rvalue_datum(bcx, "data")); + + let dest = match dest { + expr::SaveIn(d) => d, + expr::Ignore => alloc_ty(bcx, tcx.mk_mut_ptr(tcx.types.i8), + "try_result"), + }; + + // do the invoke + bcx = try_intrinsic(bcx, func.val, data.val, dest, + call_debug_location); + + fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); + return Result::new(bcx, dest); + } else { + ccx.sess().bug("expected two exprs as arguments for \ + `try` intrinsic"); + } + } + // Push the arguments. let mut llargs = Vec::new(); bcx = callee::trans_args(bcx, @@ -314,8 +353,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); - let call_debug_location = DebugLoc::At(call_info.id, call_info.span); - // These are the only intrinsic functions that diverge. if &name[..] == "abort" { let llfn = ccx.get_intrinsic(&("llvm.trap")); @@ -989,3 +1026,304 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ret } } + +fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + func: ValueRef, + data: ValueRef, + dest: ValueRef, + dloc: DebugLoc) -> Block<'blk, 'tcx> { + if bcx.sess().no_landing_pads() { + Call(bcx, func, &[data], None, dloc); + Store(bcx, C_null(Type::i8p(bcx.ccx())), dest); + bcx + } else if bcx.sess().target.target.options.is_like_msvc { + trans_msvc_try(bcx, func, data, dest, dloc) + } else { + trans_gnu_try(bcx, func, data, dest, dloc) + } +} + +// MSVC's definition of the `rust_try` function. The exact implementation here +// is a little different than the GNU (standard) version below, not only because +// of the personality function but also because of the other fiddly bits about +// SEH. LLVM also currently requires us to structure this a very particular way +// as explained below. +// +// Like with the GNU version we generate a shim wrapper +fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + func: ValueRef, + data: ValueRef, + dest: ValueRef, + dloc: DebugLoc) -> Block<'blk, 'tcx> { + let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| { + let ccx = bcx.ccx(); + let dloc = DebugLoc::None; + let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try", + try_fn_ty); + let (fcx, block_arena); + block_arena = TypedArena::new(); + fcx = new_fn_ctxt(ccx, rust_try, ast::DUMMY_NODE_ID, false, + output, ccx.tcx().mk_substs(Substs::trans_empty()), + None, &block_arena); + let bcx = init_function(&fcx, true, output); + let then = fcx.new_temp_block("then"); + let catch = fcx.new_temp_block("catch"); + let catch_return = fcx.new_temp_block("catch-return"); + let catch_resume = fcx.new_temp_block("catch-resume"); + let personality = fcx.eh_personality(); + + let eh_typeid_for = ccx.get_intrinsic(&"llvm.eh.typeid.for"); + let rust_try_filter = match bcx.tcx().lang_items.msvc_try_filter() { + Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0), + bcx.fcx.param_substs).val, + None => bcx.sess().bug("msvc_try_filter not defined"), + }; + + // Type indicator for the exception being thrown, not entirely sure + // what's going on here but it's what all the examples in LLVM use. + let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], + false); + + llvm::SetFunctionAttribute(rust_try, llvm::Attribute::NoInline); + llvm::SetFunctionAttribute(rust_try, llvm::Attribute::OptimizeNone); + let func = llvm::get_param(rust_try, 0); + let data = llvm::get_param(rust_try, 1); + + // Invoke the function, specifying our two temporary landing pads as the + // ext point. After the invoke we've terminated our basic block. + Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc); + + // All the magic happens in this landing pad, and this is basically the + // only landing pad in rust tagged with "catch" to indicate that we're + // catching an exception. The other catch handlers in the GNU version + // below just catch *all* exceptions, but that's because most exceptions + // are already filtered out by the gnu personality function. + // + // For MSVC we're just using a standard personality function that we + // can't customize (e.g. _except_handler3 or __C_specific_handler), so + // we need to do the exception filtering ourselves. This is currently + // performed by the `__rust_try_filter` function. This function, + // specified in the landingpad instruction, will be invoked by Windows + // SEH routines and will return whether the exception in question can be + // caught (aka the Rust runtime is the one that threw the exception). + // + // To get this to compile (currently LLVM segfaults if it's not in this + // particular structure), when the landingpad is executing we test to + // make sure that the ID of the exception being thrown is indeed the one + // that we were expecting. If it's not, we resume the exception, and + // otherwise we return the pointer that we got Full disclosure: It's not + // clear to me what this `llvm.eh.typeid` stuff is doing *other* then + // just allowing LLVM to compile this file without segfaulting. I would + // expect the entire landing pad to just be: + // + // %vals = landingpad ... + // %ehptr = extractvalue { i8*, i32 } %vals, 0 + // ret i8* %ehptr + // + // but apparently LLVM chokes on this, so we do the more complicated + // thing to placate it. + let vals = LandingPad(catch, lpad_ty, personality, 1); + let rust_try_filter = BitCast(catch, rust_try_filter, Type::i8p(ccx)); + AddClause(catch, vals, rust_try_filter); + let ehptr = ExtractValue(catch, vals, 0); + let sel = ExtractValue(catch, vals, 1); + let filter_sel = Call(catch, eh_typeid_for, &[rust_try_filter], None, + dloc); + let is_filter = ICmp(catch, llvm::IntEQ, sel, filter_sel, dloc); + CondBr(catch, is_filter, catch_return.llbb, catch_resume.llbb, dloc); + + // Our "catch-return" basic block is where we've determined that we + // actually need to catch this exception, in which case we just return + // the exception pointer. + Ret(catch_return, ehptr, dloc); + + // The "catch-resume" block is where we're running this landing pad but + // we actually need to not catch the exception, so just resume the + // exception to return. + Resume(catch_resume, vals); + + // On the successful branch we just return null. + Ret(then, C_null(Type::i8p(ccx)), dloc); + + return rust_try + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = Call(bcx, llfn, &[func, data], None, dloc); + Store(bcx, ret, dest); + return bcx; +} + +// Definition of the standard "try" function for Rust using the GNU-like model +// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke +// instructions). +// +// This translation is a little surprising for two reasons: +// +// 1. We always call a shim function instead of inlining the call to `invoke` +// manually here. This is done because in LLVM we're only allowed to have one +// personality per function definition. The call to the `try` intrinsic is +// being inlined into the function calling it, and that function may already +// have other personality functions in play. By calling a shim we're +// guaranteed that our shim will have the right personality function. +// +// 2. Instead of making one shim (explained above), we make two shims! The +// reason for this has to do with the technical details about the +// implementation of unwinding in the runtime, but the tl;dr; is that the +// outer shim's personality function says "catch rust exceptions" and the +// inner shim's landing pad will not `resume` the exception being thrown. +// This means that the outer shim's landing pad is never run and the inner +// shim's return value is the return value of the whole call. +// +// The double-shim aspect is currently done for implementation ease on the +// runtime side of things, and more info can be found in +// src/libstd/rt/unwind/gcc.rs. +fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + func: ValueRef, + data: ValueRef, + dest: ValueRef, + dloc: DebugLoc) -> Block<'blk, 'tcx> { + let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| { + let ccx = bcx.ccx(); + let dloc = DebugLoc::None; + + // Type indicator for the exception being thrown, not entirely sure + // what's going on here but it's what all the examples in LLVM use. + let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], + false); + + // Define the "inner try" shim + let rust_try_inner = declare::define_internal_rust_fn(ccx, + "__rust_try_inner", + try_fn_ty); + trans_rust_try(ccx, rust_try_inner, lpad_ty, bcx.fcx.eh_personality(), + output, dloc, &mut |bcx, then, catch| { + let func = llvm::get_param(rust_try_inner, 0); + let data = llvm::get_param(rust_try_inner, 1); + Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc); + C_null(Type::i8p(ccx)) + }); + + // Define the "outer try" shim. + let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try", + try_fn_ty); + let catch_pers = match bcx.tcx().lang_items.eh_personality_catch() { + Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0), + bcx.fcx.param_substs).val, + None => bcx.tcx().sess.bug("eh_personality_catch not defined"), + }; + trans_rust_try(ccx, rust_try, lpad_ty, catch_pers, output, dloc, + &mut |bcx, then, catch| { + let func = llvm::get_param(rust_try, 0); + let data = llvm::get_param(rust_try, 1); + Invoke(bcx, rust_try_inner, &[func, data], then.llbb, catch.llbb, + None, dloc) + }); + return rust_try + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = Call(bcx, llfn, &[func, data], None, dloc); + Store(bcx, ret, dest); + return bcx; + + // Translates both the inner and outer shims described above. The only + // difference between these two is the function invoked and the personality + // involved, so a common routine is shared. + // + // bcx: + // invoke %func(%args...) normal %normal unwind %unwind + // + // normal: + // ret null + // + // unwind: + // (ptr, _) = landingpad + // br (ptr != null), done, reraise + // + // done: + // ret ptr + // + // reraise: + // resume + // + // Note that the branch checking for `null` here isn't actually necessary, + // it's just an unfortunate hack to make sure that LLVM doesn't optimize too + // much. If this were not present, then LLVM would correctly deduce that our + // inner shim should be tagged with `nounwind` (as it catches all + // exceptions) and then the outer shim's `invoke` will be translated to just + // a simple call, destroying that entry for the personality function. + // + // To ensure that both shims always have an `invoke` this check against null + // confuses LLVM enough to the point that it won't infer `nounwind` and + // we'll proceed as normal. + fn trans_rust_try<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + llfn: ValueRef, + lpad_ty: Type, + personality: ValueRef, + output: ty::FnOutput<'tcx>, + dloc: DebugLoc, + invoke: &mut FnMut(Block, Block, Block) -> ValueRef) { + let (fcx, block_arena); + block_arena = TypedArena::new(); + fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, + output, ccx.tcx().mk_substs(Substs::trans_empty()), + None, &block_arena); + let bcx = init_function(&fcx, true, output); + let then = bcx.fcx.new_temp_block("then"); + let catch = bcx.fcx.new_temp_block("catch"); + let reraise = bcx.fcx.new_temp_block("reraise"); + let catch_return = bcx.fcx.new_temp_block("catch-return"); + + let invoke_ret = invoke(bcx, then, catch); + Ret(then, invoke_ret, dloc); + let vals = LandingPad(catch, lpad_ty, personality, 1); + AddClause(catch, vals, C_null(Type::i8p(ccx))); + let ptr = ExtractValue(catch, vals, 0); + let valid = ICmp(catch, llvm::IntNE, ptr, C_null(Type::i8p(ccx)), dloc); + CondBr(catch, valid, catch_return.llbb, reraise.llbb, dloc); + Ret(catch_return, ptr, dloc); + Resume(reraise, vals); + } +} + +// Helper to generate the `Ty` associated with `rust_Try` +fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, + f: &mut FnMut(Ty<'tcx>, + ty::FnOutput<'tcx>) -> ValueRef) + -> ValueRef { + let ccx = fcx.ccx; + if let Some(llfn) = *ccx.rust_try_fn().borrow() { + return llfn + } + + // Define the types up front for the signatures of the rust_try and + // rust_try_inner functions. + let tcx = ccx.tcx(); + let i8p = tcx.mk_mut_ptr(tcx.types.i8); + let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: vec![i8p], + output: ty::FnOutput::FnConverging(tcx.mk_nil()), + variadic: false, + }), + }); + let fn_ty = tcx.mk_fn(None, fn_ty); + let output = ty::FnOutput::FnConverging(i8p); + let try_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: vec![fn_ty, i8p], + output: output, + variadic: false, + }), + }); + let rust_try = f(tcx.mk_fn(None, try_fn_ty), output); + *ccx.rust_try_fn().borrow_mut() = Some(rust_try); + return rust_try +} diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 1fa996f76b9a2..8901361b27976 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -550,9 +550,7 @@ fn trans_object_shim<'a, 'tcx>( let shim_fn_ty = tcx.mk_fn(None, fty); let method_bare_fn_ty = tcx.mk_fn(None, method_ty); let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); - let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); - }); + let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty); let sig = ccx.tcx().erase_late_bound_regions(&fty.sig); diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 98fe57ec31446..217181da1421a 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -137,10 +137,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let lldecl = if abi != abi::Rust { foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..]) } else { - // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below. - declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", s)); - }) + // FIXME(nagisa): perhaps needs a more fine grained selection? See + // setup_lldecl below. + declare::define_internal_rust_fn(ccx, &s, mono_ty) }; ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e4ae2c97fe057..8f0eef8ba0b38 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -50,6 +50,7 @@ use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS}; use middle::const_eval::{self, ConstVal}; +use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def; use middle::implicator::object_region_bounds; use middle::resolve_lifetime as rl; @@ -1112,7 +1113,7 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, // any ambiguity. fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, ty_param_node_id: ast::NodeId, - ty_param_name: Option, + ty_param_name: ast::Name, assoc_name: ast::Name, span: Span) -> Result, ErrorReported> @@ -1138,21 +1139,11 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); - if let Some(s) = ty_param_name { - // borrowck doesn't like this any other way - one_bound_for_assoc_type(tcx, - suitable_bounds, - &token::get_name(s), - &token::get_name(assoc_name), - span) - } else { - one_bound_for_assoc_type(tcx, - suitable_bounds, - "Self", - &token::get_name(assoc_name), - span) - - } + one_bound_for_assoc_type(tcx, + suitable_bounds, + &token::get_name(ty_param_name), + &token::get_name(assoc_name), + span) } @@ -1251,7 +1242,11 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => { assert_eq!(trait_did.krate, ast::LOCAL_CRATE); - match find_bound_for_assoc_item(this, trait_did.node, None, assoc_name, span) { + match find_bound_for_assoc_item(this, + trait_did.node, + token::special_idents::type_self.name, + assoc_name, + span) { Ok(bound) => bound, Err(ErrorReported) => return (tcx.types.err, ty_path_def), } @@ -1260,7 +1255,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, assert_eq!(param_did.krate, ast::LOCAL_CRATE); match find_bound_for_assoc_item(this, param_did.node, - Some(param_name), + param_name, assoc_name, span) { Ok(bound) => bound, @@ -1629,7 +1624,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, ty } ast::TyFixedLengthVec(ref ty, ref e) => { - match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.usize)) { + let hint = UncheckedExprHint(tcx.types.usize); + match const_eval::eval_const_expr_partial(tcx, &e, hint) { Ok(r) => { match r { ConstVal::Int(i) => diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a995401cf5c81..c4b31d578dbfd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::const_eval; use middle::def; use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; @@ -23,7 +22,7 @@ use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_typ use require_same_types; use util::nodemap::FnvHashMap; -use std::cmp::{self, Ordering}; +use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; use syntax::ast_util; @@ -130,18 +129,6 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, fcx.write_ty(pat.id, common_type); - // Finally we evaluate the constants and check that the range is non-empty. - let get_substs = |id| fcx.item_substs()[&id].substs.clone(); - match const_eval::compare_lit_exprs(tcx, begin, end, Some(&common_type), get_substs) { - Some(Ordering::Less) | - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => { - span_err!(tcx.sess, begin.span, E0030, - "lower range bound must be less than or equal to upper"); - } - None => tcx.sess.span_bug(begin.span, "literals of different types in range pat") - } - // subtyping doesn't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9042cedccc857..fdeed657e071b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -114,7 +114,6 @@ use syntax::attr::AttrMetaMethods; use syntax::ast::{self, DefId, Visibility}; use syntax::ast_util::{self, local_def}; use syntax::codemap::{self, Span}; -use syntax::feature_gate; use syntax::owned_slice::OwnedSlice; use syntax::parse::token; use syntax::print::pprust; @@ -3074,15 +3073,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, tcx.lang_items.neg_trait(), expr, &**oprnd, oprnd_t, unop); } - if let ty::TyUint(_) = oprnd_t.sty { - if !tcx.sess.features.borrow().negate_unsigned { - feature_gate::emit_feature_err( - &tcx.sess.parse_sess.span_diagnostic, - "negate_unsigned", - expr.span, - "unary negation of unsigned integers may be removed in the future"); - } - } } } } @@ -5096,6 +5086,21 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ty::BrAnon(0))), param(ccx, 0))], tcx.types.u64), + "try" => { + let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); + let fn_ty = ty::BareFnTy { + unsafety: ast::Unsafety::Normal, + abi: abi::Rust, + sig: ty::Binder(FnSig { + inputs: vec![mut_u8], + output: ty::FnOutput::FnConverging(tcx.mk_nil()), + variadic: false, + }), + }; + let fn_ty = tcx.mk_bare_fn(fn_ty); + (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8) + } + ref other => { span_err!(tcx.sess, it.span, E0093, "unrecognized intrinsic function: `{}`", *other); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index a002ed311e8c5..f865de522b28a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -169,24 +169,6 @@ match string { ``` "##, -E0030: r##" -When matching against a range, the compiler verifies that the range is -non-empty. Range patterns include both end-points, so this is equivalent to -requiring the start of the range to be less than or equal to the end of the -range. - -For example: - -``` -match 5u32 { - // This range is ok, albeit pointless. - 1 ... 1 => ... - // This range is empty, and the compiler can tell. - 1000 ... 5 => ... -} -``` -"##, - E0033: r##" This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a pattern. Every trait defines a type, but because the @@ -1476,6 +1458,33 @@ return, for example with a `loop` that never breaks or a call to another diverging function (such as `panic!()`). "##, +E0172: r##" +This error means that an attempt was made to specify the type of a variable with +a combination of a concrete type and a trait. Consider the following example: + +``` +fn foo(bar: i32+std::fmt::Display) {} +``` + +The code is trying to specify that we want to receive a signed 32-bit integer +which also implements `Display`. This doesn't make sense: when we pass `i32`, a +concrete type, it implicitly includes all of the traits that it implements. +This includes `Display`, `Debug`, `Clone`, and a host of others. + +If `i32` implements the trait we desire, there's no need to specify the trait +separately. If it does not, then we need to `impl` the trait for `i32` before +passing it into `foo`. Either way, a fixed definition for `foo` will look like +the following: + +``` +fn foo(bar: i32) {} +``` + +To learn more about traits, take a look at the Book: + +https://doc.rust-lang.org/book/traits.html +"##, + E0178: r##" In types, the `+` type operator has low precedence, so it is often necessary to use parentheses. @@ -2196,7 +2205,6 @@ register_diagnostics! { E0164, E0167, E0168, - E0172, E0173, // manual implementations of unboxed closure traits are experimental E0174, // explicit use of unboxed closure methods are experimental E0182, diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 2596620d39d3d..42c19ee6a204d 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Character manipulation (`char` type, Unicode Scalar Value) +//! A Unicode scalar value //! //! This module provides the `CharExt` trait, as well as its //! implementation for the primitive `char` type, in order to allow //! basic character manipulation. //! -//! A `char` actually represents a -//! *[Unicode Scalar -//! Value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can +//! A `char` represents a +//! *[Unicode scalar +//! value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can //! contain any Unicode code point except high-surrogate and low-surrogate code //! points. //! @@ -24,9 +24,10 @@ //! (inclusive) are allowed. A `char` can always be safely cast to a `u32`; //! however the converse is not always true due to the above range limits //! and, as such, should be performed via the `from_u32` function. +//! +//! *[See also the `char` primitive type](../primitive.char.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "char")] use core::char::CharExt as C; use core::option::Option::{self, Some, None}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3cc24550297ce..d4eeaa1de109c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1947,6 +1947,10 @@ impl Span { impl Clean for syntax::codemap::Span { fn clean(&self, cx: &DocContext) -> Span { + if *self == DUMMY_SP { + return Span::empty(); + } + let cm = cx.sess().codemap(); let filename = cm.span_to_filename(*self); let lo = cm.lookup_char_pos(self.lo); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fc06dc347b5ed..2255a2e969f1a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -540,6 +540,19 @@ impl fmt::Display for clean::Type { } } +impl fmt::Display for clean::Impl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "impl{} ", self.generics)); + if let Some(ref ty) = self.trait_ { + try!(write!(f, "{}{} for ", + if self.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" }, + *ty)); + } + try!(write!(f, "{}{}", self.for_, WhereClause(&self.generics))); + Ok(()) + } +} + impl fmt::Display for clean::Arguments { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (i, input) in self.values.iter().enumerate() { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 07e3ae975d66d..57c0db8f96e66 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -118,11 +118,8 @@ pub enum ExternalLocation { /// Metadata about an implementor of a trait. pub struct Implementor { pub def_id: ast::DefId, - pub generics: clean::Generics, - pub trait_: clean::Type, - pub for_: clean::Type, pub stability: Option, - pub polarity: Option, + pub impl_: clean::Impl, } /// Metadata about implementations for a type. @@ -644,10 +641,7 @@ fn write_shared(cx: &Context, // going on). If they're in different crates then the crate defining // the trait will be interested in our implementation. if imp.def_id.krate == did.krate { continue } - try!(write!(&mut f, r#""impl{} {}{} for {}","#, - imp.generics, - if imp.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" }, - imp.trait_, imp.for_)); + try!(write!(&mut f, r#""{}","#, imp.impl_)); } try!(writeln!(&mut f, r"];")); try!(writeln!(&mut f, "{}", r" @@ -888,11 +882,8 @@ impl DocFolder for Cache { Some(clean::ResolvedPath{ did, .. }) => { self.implementors.entry(did).or_insert(vec![]).push(Implementor { def_id: item.def_id, - generics: i.generics.clone(), - trait_: i.trait_.as_ref().unwrap().clone(), - for_: i.for_.clone(), stability: item.stability.clone(), - polarity: i.polarity.clone(), + impl_: i.clone(), }); } Some(..) | None => {} @@ -1910,8 +1901,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, match cache.implementors.get(&it.def_id) { Some(implementors) => { for i in implementors { - try!(writeln!(w, "
  • impl{} {} for {}{}
  • ", - i.generics, i.trait_, i.for_, WhereClause(&i.generics))); + try!(writeln!(w, "
  • {}
  • ", i.impl_)); } } None => {} @@ -2335,16 +2325,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result { fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink, render_header: bool) -> fmt::Result { if render_header { - try!(write!(w, "

    impl{} ", - i.impl_.generics)); - if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity { - try!(write!(w, "!")); - } - if let Some(ref ty) = i.impl_.trait_ { - try!(write!(w, "{} for ", *ty)); - } - try!(write!(w, "{}{}

    ", i.impl_.for_, - WhereClause(&i.impl_.generics))); + try!(write!(w, "

    {}

    ", i.impl_)); if let Some(ref dox) = i.dox { try!(write!(w, "
    {}
    ", Markdown(dox))); } diff --git a/src/libstd/array.rs b/src/libstd/array.rs deleted file mode 100644 index 0dfcc72e37910..0000000000000 --- a/src/libstd/array.rs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -//! A fixed-size array is denoted `[T; N]` for the element type `T` and -//! the compile time constant size `N`. The size must be zero or positive. -//! -//! Arrays values are created either with an explicit expression that lists -//! each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat -//! expression requires that the element type is `Copy`. -//! -//! The type `[T; N]` is `Copy` if `T: Copy`. -//! -//! Arrays of sizes from 0 to 32 (inclusive) implement the following traits -//! if the element type allows it: -//! -//! - `Clone` -//! - `Debug` -//! - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`) -//! - `PartialEq`, `PartialOrd`, `Ord`, `Eq` -//! - `Hash` -//! - `AsRef`, `AsMut` -//! -//! Arrays dereference to [slices (`[T]`)][slice], so their methods can be called -//! on arrays. -//! -//! [slice]: primitive.slice.html -//! -//! Rust does not currently support generics over the size of an array type. -//! -//! # Examples -//! -//! ``` -//! let mut array: [i32; 3] = [0; 3]; -//! -//! array[1] = 1; -//! array[2] = 2; -//! -//! assert_eq!([1, 2], &array[1..]); -//! -//! // This loop prints: 0 1 2 -//! for x in &array { -//! print!("{} ", x); -//! } -//! -//! ``` -//! - -#![doc(primitive = "array")] diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 2c78b2894311d..e5f2fcbae8394 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -24,8 +24,8 @@ use ffi::OsString; use io::{self, SeekFrom, Seek, Read, Write}; use path::{Path, PathBuf}; use sys::fs as fs_imp; -use sys_common::{AsInnerMut, FromInner, AsInner}; use sys_common::io::read_to_end_uninitialized; +use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; use vec::Vec; /// A reference to an open file on the filesystem. @@ -317,6 +317,11 @@ impl FromInner for File { File { inner: f } } } +impl IntoInner for File { + fn into_inner(self) -> fs_imp::File { + self.inner + } +} impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index d6561ebb489d7..c25aa35ffbe3b 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -252,14 +252,49 @@ impl Seek for BufReader { } } -/// Wraps a Writer and buffers output to it. +/// Wraps a writer and buffers its output. /// -/// It can be excessively inefficient to work directly with a `Write`. For -/// example, every call to `write` on `TcpStream` results in a system call. A -/// `BufWriter` keeps an in memory buffer of data and writes it to the -/// underlying `Write` in large, infrequent batches. +/// It can be excessively inefficient to work directly with something that +/// implements `Write`. For example, every call to `write` on `TcpStream` +/// results in a system call. A `BufWriter` keeps an in-memory buffer of data +/// and writes it to an underlying writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. +/// +/// # Examples +/// +/// Let's write the numbers one through ten to a `TcpStream`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// Because we're not buffering, we write each one in turn, incurring the +/// overhead of a system call per byte written. We can fix this with a +/// `BufWriter`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped +/// together by the buffer, and will all be written out in one system call when +/// the `stream` is dropped. #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { inner: Option, @@ -269,18 +304,60 @@ pub struct BufWriter { /// An error returned by `into_inner` which combines an error that /// happened while writing out the buffer, and the buffered writer object /// which may be used to recover from the condition. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// // do stuff with the stream +/// +/// // we want to get our `TcpStream` back, so let's try: +/// +/// let stream = match stream.into_inner() { +/// Ok(s) => s, +/// Err(e) => { +/// // Here, e is an IntoInnerError +/// panic!("An error occurred"); +/// } +/// }; +/// ``` #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoInnerError(W, Error); impl BufWriter { /// Creates a new `BufWriter` with a default buffer capacity. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } /// Creates a new `BufWriter` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with a buffer of a hundred bytes. + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let mut buffer = BufWriter::with_capacity(100, stream); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> BufWriter { BufWriter { @@ -313,6 +390,18 @@ impl BufWriter { } /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_ref(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } @@ -321,12 +410,36 @@ impl BufWriter { /// # Warning /// /// It is inadvisable to directly write to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_mut(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } /// Unwraps this `BufWriter`, returning the underlying writer. /// /// The buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(mut self) -> Result>> { match self.flush_buf() { @@ -384,9 +497,34 @@ impl Drop for BufWriter { } impl IntoInnerError { - /// Returns the error which caused the call to `into_inner` to fail. + /// Returns the error which caused the call to `into_inner()` to fail. /// /// This error was returned when attempting to write the internal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's log the inner error. + /// // + /// // We'll just 'log' to stdout for this example. + /// println!("{}", e.error()); + /// + /// panic!("An unexpected error occurred."); + /// } + /// }; + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn error(&self) -> &Error { &self.1 } @@ -394,6 +532,32 @@ impl IntoInnerError { /// /// The returned object can be used for error recovery, such as /// re-inspecting the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is a IntoInnerError, let's re-examine the buffer: + /// let buffer = e.into_inner(); + /// + /// // do stuff to try to recover + /// + /// // afterwards, let's just return the stream + /// buffer.into_inner().unwrap() + /// } + /// }; + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> W { self.0 } } @@ -417,17 +581,74 @@ impl fmt::Display for IntoInnerError { } } -/// Wraps a Writer and buffers output to it, flushing whenever a newline +/// Wraps a writer and buffers output to it, flushing whenever a newline /// (`0x0a`, `'\n'`) is detected. /// -/// The buffer will be written out when the writer is dropped. +/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output. +/// But it only does this batched write when it goes out of scope, or when the +/// internal buffer is full. Sometimes, you'd prefer to write each line as it's +/// completed, rather than the entire buffer at once. Enter `LineWriter`. It +/// does exactly that. +/// +/// [bufwriter]: struct.BufWriter.html +/// +/// If there's still a partial line in the buffer when the `LineWriter` is +/// dropped, it will flush those contents. +/// +/// # Examples +/// +/// We can use `LineWriter` to write one line at a time, significantly +/// reducing the number of actual writes to the file. +/// +/// ``` +/// use std::fs::File; +/// use std::io::prelude::*; +/// use std::io::LineWriter; +/// +/// # fn foo() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh +/// Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference."; +/// +/// let file = try!(File::create("poem.txt")); +/// let mut file = LineWriter::new(file); +/// +/// for &byte in road_not_taken.iter() { +/// file.write(&[byte]).unwrap(); +/// } +/// +/// // let's check we did the right thing. +/// let mut file = try!(File::open("poem.txt")); +/// let mut contents = String::new(); +/// +/// try!(file.read_to_string(&mut contents)); +/// +/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { inner: BufWriter, } impl LineWriter { - /// Creates a new `LineWriter` + /// Creates a new `LineWriter`. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> LineWriter { // Lines typically aren't that long, don't use a giant buffer @@ -436,12 +657,40 @@ impl LineWriter { /// Creates a new `LineWriter` with a specified capacity for the internal /// buffer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::with_capacity(100, file); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> LineWriter { LineWriter { inner: BufWriter::with_capacity(cap, inner) } } /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.get_ref() } @@ -449,12 +698,44 @@ impl LineWriter { /// /// Caution must be taken when calling methods on the mutable reference /// returned as extra writes could corrupt the output stream. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let mut file = LineWriter::new(file); + /// + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } /// Unwraps this `LineWriter`, returning the underlying writer. /// /// The internal buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// + /// let writer: LineWriter = LineWriter::new(file); + /// + /// let file: File = try!(writer.into_inner()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 2447473103101..fbdfdeaaef4f2 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -9,6 +9,235 @@ // except according to those terms. //! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `std::io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`][read] and [`Write`][write] traits, which provide the +//! most general interface for reading and writing input and output. +//! +//! [read]: trait.Read.html +//! [write]: trait.Write.html +//! +//! # Read and Write +//! +//! Because they are traits, they're implemented by a number of other types, +//! and you can implement them for your types too. As such, you'll see a +//! few different types of I/O throughout the documentation in this module: +//! `File`s, `TcpStream`s, and somtimes even `Vec`s. For example, `Read` +//! adds a `read()` method, which we can use on `File`s: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! `Read` and `Write` are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the `Read` trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`][seek] +//! and [`BufRead`][bufread]. Both of these build on top of a reader to control +//! how the reading happens. `Seek` lets you control where the next byte is +//! coming from: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::SeekFrom; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! try!(f.seek(SeekFrom::End(-10))); +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! [seek]: trait.Seek.html +//! [bufread]: trait.BufRead.html +//! +//! `BufRead` uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, `BufReader` works with the `BufRead` trait to add extra +//! methods to any reader: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::open("foo.txt")); +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); +//! +//! // read a line into buffer +//! try!(reader.read_line(&mut buffer)); +//! +//! println!("{}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! `BufWriter` doesn't add any new ways of writing, it just buffers every call +//! to [`write()`][write]: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufWriter; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::create("foo.txt")); +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! try!(writer.write(&[42])); +//! +//! } // the buffer is flushed once writer goes out of scope +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! [write]: trait.Write.html#tymethod.write +//! +//! ## Standard input and output +//! +//! A very common source of input is standard input: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! # Ok(()) +//! # } +//! ``` +//! +//! And a very common source of output is standard output: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::stdout().write(&[42])); +//! # Ok(()) +//! # } +//! ``` +//! +//! Of course, using `io::stdout()` directly is less comon than something like +//! `println!`. +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, `Lines` is used to split over +//! lines: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::open("foo.txt")); +//! let mut reader = BufReader::new(f); +//! +//! for line in reader.lines() { +//! let line = try!(line); +//! println!("{}", line); +//! } +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Functions +//! +//! There are a number of [functions][functions] that offer access to various +//! features. For example, we can use three of these functions to copy everything +//! from standard input to standard output: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::copy(&mut io::stdin(), &mut io::stdout())); +//! # Ok(()) +//! # } +//! ``` +//! +//! [functions]: #functions +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`][result]. This type is used +//! as the return type of many `std::io` functions that can cause an error, and +//! can be returned from your own functions as well. Many of the examples in this +//! module use the [`try!`][try] macro: +//! +//! ``` +//! use std::io; +//! +//! fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input()`, `io::Result<()>`, is a very common type +//! for functions which don't have a 'real' return value, but do want to return +//! errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use use `()`. +//! +//! [result]: type.Result.html +//! [try]: macro.try!.html #![stable(feature = "rust1", since = "1.0.0")] @@ -1167,7 +1396,10 @@ pub trait BufRead: Read { /// A `Write` adaptor which will write data to multiple locations. /// -/// For more information, see `Write::broadcast`. +/// This struct is generally created by calling [`broadcast()`][broadcast] on a +/// writer. Please see the documentation of `broadcast()` for more details. +/// +/// [broadcast]: trait.Write.html#method.broadcast #[unstable(feature = "io", reason = "awaiting stability of Write::broadcast")] pub struct Broadcast { first: T, @@ -1188,9 +1420,12 @@ impl Write for Broadcast { } } -/// Adaptor to chain together two instances of `Read`. +/// Adaptor to chain together two readers. +/// +/// This struct is generally created by calling [`chain()`][chain] on a reader. +/// Please see the documentation of `chain()` for more details. /// -/// For more information, see `Read::chain`. +/// [chain]: trait.Read.html#method.chain #[stable(feature = "rust1", since = "1.0.0")] pub struct Chain { first: T, @@ -1213,7 +1448,10 @@ impl Read for Chain { /// Reader adaptor which limits the bytes read from an underlying reader. /// -/// For more information, see `Read::take`. +/// This struct is generally created by calling [`take()`][take] on a reader. +/// Please see the documentation of `take()` for more details. +/// +/// [take]: trait.Read.html#method.take #[stable(feature = "rust1", since = "1.0.0")] pub struct Take { inner: T, @@ -1266,7 +1504,10 @@ impl BufRead for Take { /// An adaptor which will emit all read data to a specified writer as well. /// -/// For more information see `Read::tee` +/// This struct is generally created by calling [`tee()`][tee] on a reader. +/// Please see the documentation of `tee()` for more details. +/// +/// [tee]: trait.Read.html#method.tee #[unstable(feature = "io", reason = "awaiting stability of Read::tee")] pub struct Tee { reader: R, @@ -1283,9 +1524,12 @@ impl Read for Tee { } } -/// A bridge from implementations of `Read` to an `Iterator` of `u8`. +/// An iterator over `u8` values of a reader. /// -/// See `Read::bytes` for more information. +/// This struct is generally created by calling [`bytes()`][bytes] on a reader. +/// Please see the documentation of `bytes()` for more details. +/// +/// [bytes]: trait.Read.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] pub struct Bytes { inner: R, @@ -1305,9 +1549,12 @@ impl Iterator for Bytes { } } -/// A bridge from implementations of `Read` to an `Iterator` of `char`. +/// An iterator over the `char`s of a reader. +/// +/// This struct is generally created by calling [`chars()`][chars] on a reader. +/// Please see the documentation of `chars()` for more details. /// -/// See `Read::chars` for more information. +/// [chars]: trait.Read.html#method.chars #[unstable(feature = "io", reason = "awaiting stability of Read::chars")] pub struct Chars { inner: R, @@ -1389,7 +1636,10 @@ impl fmt::Display for CharsError { /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// -/// See `BufRead::split` for more information. +/// This struct is generally created by calling [`split()`][split] on a +/// `BufRead`. Please see the documentation of `split()` for more details. +/// +/// [split]: trait.BufRead.html#method.split #[stable(feature = "rust1", since = "1.0.0")] pub struct Split { buf: B, @@ -1415,10 +1665,12 @@ impl Iterator for Split { } } -/// An iterator over the lines of an instance of `BufRead` split on a newline -/// byte. +/// An iterator over the lines of an instance of `BufRead`. +/// +/// This struct is generally created by calling [`lines()`][lines] on a +/// `BufRead`. Please see the documentation of `lines()` for more details. /// -/// See `BufRead::lines` for more information. +/// [lines]: trait.BufRead.html#method.lines #[stable(feature = "rust1", since = "1.0.0")] pub struct Lines { buf: B, diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index c0bced26beffa..dc29811ed5ba1 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -61,6 +61,11 @@ pub fn copy(reader: &mut R, writer: &mut W) -> io::Result for TcpStream { fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) } } +impl IntoInner for TcpStream { + fn into_inner(self) -> net_imp::TcpStream { self.0 } +} + impl fmt::Debug for TcpStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) @@ -298,6 +302,10 @@ impl FromInner for TcpListener { } } +impl IntoInner for TcpListener { + fn into_inner(self) -> net_imp::TcpListener { self.0 } +} + impl fmt::Debug for TcpListener { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 0545175d9aee9..a98ccc3873597 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -17,7 +17,7 @@ use fmt; use io::{self, Error, ErrorKind}; use net::{ToSocketAddrs, SocketAddr, IpAddr}; use sys_common::net as net_imp; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; /// A User Datagram Protocol socket. @@ -174,6 +174,10 @@ impl FromInner for UdpSocket { fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } } +impl IntoInner for UdpSocket { + fn into_inner(self) -> net_imp::UdpSocket { self.0 } +} + impl fmt::Debug for UdpSocket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index c2fb2fa417598..b8a70d756efff 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for 32-bits floats (`f32` type) +//! The 32-bit floating point type. +//! +//! *[See also the `f32` primitive type](../primitive.f32.html).* #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] #![allow(unsigned_negation)] -#![doc(primitive = "f32")] use prelude::v1::*; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 41c0fcb9797a6..4f2f59659ac80 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for 64-bits floats (`f64` type) +//! The 64-bit floating point type. +//! +//! *[See also the `f64` primitive type](../primitive.f64.html).* #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![doc(primitive = "f64")] use prelude::v1::*; diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index 498f19b9b8307..eb53e0821f2a6 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 16-bits integers (`i16` type) +//! The 16-bit signed integer type. +//! +//! *[See also the `i16` primitive type](../primitive.i16.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i16")] pub use core::i16::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index aea1e92117bb0..3c9eedf38c7cd 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 32-bits integers (`i32` type) +//! The 32-bit signed integer type. +//! +//! *[See also the `i32` primitive type](../primitive.i32.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i32")] pub use core::i32::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index 43794345fe7a4..2df7478a820bf 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 64-bits integers (`i64` type) +//! The 64-bit signed integer type. +//! +//! *[See also the `i64` primitive type](../primitive.i64.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i64")] pub use core::i64::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index 1b03bf6f4f009..4e4bee8a791e4 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 8-bits integers (`i8` type) +//! The 8-bit signed integer type. +//! +//! *[See also the `i8` primitive type](../primitive.i8.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i8")] pub use core::i8::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/isize.rs b/src/libstd/num/isize.rs index aa89f858f6f63..d46b6b80d0d25 100644 --- a/src/libstd/num/isize.rs +++ b/src/libstd/num/isize.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for pointer-sized signed integers (`isize` type) +//! The pointer-sized signed integer type. +//! +//! *[See also the `isize` primitive type](../primitive.isize.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "isize")] pub use core::isize::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index 3fda77fb69c40..893618aeffafd 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 16-bits integers (`u16` type) +//! The 16-bit unsigned integer type. +//! +//! *[See also the `u16` primitive type](../primitive.u16.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u16")] pub use core::u16::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 8610f0c01473f..2da2551969657 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 32-bits integers (`u32` type) +//! The 32-bit unsigned integer type. +//! +//! *[See also the `u32` primitive type](../primitive.u32.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u32")] pub use core::u32::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index 3587b06965624..26a8b53739403 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 64-bits integer (`u64` type) +//! The 64-bit unsigned integer type. +//! +//! *[See also the `u64` primitive type](../primitive.u64.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u64")] pub use core::u64::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index 6a285e8299c1e..385754b93a04b 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 8-bits integers (`u8` type) +//! The 8-bit unsigned integer type. +//! +//! *[See also the `u8` primitive type](../primitive.u8.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u8")] pub use core::u8::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 555a5cc3e20e9..902c78c0a46f8 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -9,7 +9,6 @@ // except according to those terms. #![doc(hidden)] -#![allow(unsigned_negation)] macro_rules! uint_module { ($T:ident) => ( diff --git a/src/libstd/num/usize.rs b/src/libstd/num/usize.rs index b54d8ae96c5cf..6960ba3b8296b 100644 --- a/src/libstd/num/usize.rs +++ b/src/libstd/num/usize.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for pointer-sized unsigned integers (`usize` type) +//! The pointer-sized unsigned integer type. +//! +//! *[See also the `usize` primitive type](../primitive.usize.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "usize")] pub use core::usize::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs new file mode 100644 index 0000000000000..066b2b576da49 --- /dev/null +++ b/src/libstd/primitive_docs.rs @@ -0,0 +1,420 @@ +// 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. + +#[doc(primitive = "bool")] +// +/// The boolean type. +/// +mod prim_bool { } + +#[doc(primitive = "char")] +// +/// A Unicode scalar value. +/// +/// A `char` represents a +/// *[Unicode scalar +/// value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can +/// contain any Unicode code point except high-surrogate and low-surrogate code +/// points. +/// +/// As such, only values in the ranges \[0x0,0xD7FF\] and \[0xE000,0x10FFFF\] +/// (inclusive) are allowed. A `char` can always be safely cast to a `u32`; +/// however the converse is not always true due to the above range limits +/// and, as such, should be performed via the `from_u32` function. +/// +/// *[See also the `std::char` module](char/index.html).* +/// +mod prim_char { } + +#[doc(primitive = "unit")] +// +/// The `()` type, sometimes called "unit" or "nil". +/// +/// The `()` type has exactly one value `()`, and is used when there +/// is no other meaningful value that could be returned. `()` is most +/// commonly seen implicitly: functions without a `-> ...` implicitly +/// have return type `()`, that is, these are equivalent: +/// +/// ```rust +/// fn long() -> () {} +/// +/// fn short() {} +/// ``` +/// +/// The semicolon `;` can be used to discard the result of an +/// expression at the end of a block, making the expression (and thus +/// the block) evaluate to `()`. For example, +/// +/// ```rust +/// fn returns_i64() -> i64 { +/// 1i64 +/// } +/// fn returns_unit() { +/// 1i64; +/// } +/// +/// let is_i64 = { +/// returns_i64() +/// }; +/// let is_unit = { +/// returns_i64(); +/// }; +/// ``` +/// +mod prim_unit { } + +#[doc(primitive = "pointer")] +// +/// Raw, unsafe pointers, `*const T`, and `*mut T`. +/// +/// Working with raw pointers in Rust is uncommon, +/// typically limited to a few patterns. +/// +/// Use the `null` function to create null pointers, and the `is_null` method +/// of the `*const T` type to check for null. The `*const T` type also defines +/// the `offset` method, for pointer math. +/// +/// # Common ways to create raw pointers +/// +/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). +/// +/// ``` +/// let my_num: i32 = 10; +/// let my_num_ptr: *const i32 = &my_num; +/// let mut my_speed: i32 = 88; +/// let my_speed_ptr: *mut i32 = &mut my_speed; +/// ``` +/// +/// To get a pointer to a boxed value, dereference the box: +/// +/// ``` +/// let my_num: Box = Box::new(10); +/// let my_num_ptr: *const i32 = &*my_num; +/// let mut my_speed: Box = Box::new(88); +/// let my_speed_ptr: *mut i32 = &mut *my_speed; +/// ``` +/// +/// This does not take ownership of the original allocation +/// and requires no resource management later, +/// but you must not use the pointer after its lifetime. +/// +/// ## 2. Consume a box (`Box`). +/// +/// The `into_raw` function consumes a box and returns +/// the raw pointer. It doesn't destroy `T` or deallocate any memory. +/// +/// ``` +/// # #![feature(box_raw)] +/// let my_speed: Box = Box::new(88); +/// let my_speed: *mut i32 = Box::into_raw(my_speed); +/// +/// // By taking ownership of the original `Box` though +/// // we are obligated to put it together later to be destroyed. +/// unsafe { +/// drop(Box::from_raw(my_speed)); +/// } +/// ``` +/// +/// Note that here the call to `drop` is for clarity - it indicates +/// that we are done with the given value and it should be destroyed. +/// +/// ## 3. Get it from C. +/// +/// ``` +/// # #![feature(libc)] +/// extern crate libc; +/// +/// use std::mem; +/// +/// fn main() { +/// unsafe { +/// let my_num: *mut i32 = libc::malloc(mem::size_of::() as libc::size_t) as *mut i32; +/// if my_num.is_null() { +/// panic!("failed to allocate memory"); +/// } +/// libc::free(my_num as *mut libc::c_void); +/// } +/// } +/// ``` +/// +/// Usually you wouldn't literally use `malloc` and `free` from Rust, +/// but C APIs hand out a lot of pointers generally, so are a common source +/// of raw pointers in Rust. +/// +/// *[See also the `std::ptr` module](ptr/index.html).* +/// +mod prim_pointer { } + +#[doc(primitive = "array")] +// +/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and +/// the non-negative compile time constant size, `N`. +/// +/// Arrays values are created either with an explicit expression that lists +/// each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat +/// expression requires that the element type is `Copy`. +/// +/// The type `[T; N]` is `Copy` if `T: Copy`. +/// +/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits +/// if the element type allows it: +/// +/// - `Clone` +/// - `Debug` +/// - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`) +/// - `PartialEq`, `PartialOrd`, `Ord`, `Eq` +/// - `Hash` +/// - `AsRef`, `AsMut` +/// +/// Arrays dereference to [slices (`[T]`)][slice], so their methods can be called +/// on arrays. +/// +/// [slice]: primitive.slice.html +/// +/// Rust does not currently support generics over the size of an array type. +/// +/// # Examples +/// +/// ``` +/// let mut array: [i32; 3] = [0; 3]; +/// +/// array[1] = 1; +/// array[2] = 2; +/// +/// assert_eq!([1, 2], &array[1..]); +/// +/// // This loop prints: 0 1 2 +/// for x in &array { +/// print!("{} ", x); +/// } +/// +/// ``` +/// +mod prim_array { } + +#[doc(primitive = "slice")] +// +/// A dynamically-sized view into a contiguous sequence, `[T]`. +/// +/// Slices are a view into a block of memory represented as a pointer and a +/// length. +/// +/// ``` +/// // slicing a Vec +/// let vec = vec![1, 2, 3]; +/// let int_slice = &vec[..]; +/// // coercing an array to a slice +/// let str_slice: &[&str] = &["one", "two", "three"]; +/// ``` +/// +/// Slices are either mutable or shared. The shared slice type is `&[T]`, +/// while the mutable slice type is `&mut [T]`, where `T` represents the element +/// type. For example, you can mutate the block of memory that a mutable slice +/// points to: +/// +/// ``` +/// let x = &mut [1, 2, 3]; +/// x[1] = 7; +/// assert_eq!(x, &[1, 7, 3]); +/// ``` +/// +/// *[See also the `std::slice` module](slice/index.html).* +/// +mod prim_slice { } + +#[doc(primitive = "str")] +// +/// Unicode string slices. +/// +/// Rust's `str` type is one of the core primitive types of the language. `&str` +/// is the borrowed string type. This type of string can only be created from +/// other strings, unless it is a `&'static str` (see below). It is not possible +/// to move out of borrowed strings because they are owned elsewhere. +/// +/// # Examples +/// +/// Here's some code that uses a `&str`: +/// +/// ``` +/// let s = "Hello, world."; +/// ``` +/// +/// This `&str` is a `&'static str`, which is the type of string literals. +/// They're `'static` because literals are available for the entire lifetime of +/// the program. +/// +/// You can get a non-`'static` `&str` by taking a slice of a `String`: +/// +/// ``` +/// let some_string = "Hello, world.".to_string(); +/// let s = &some_string; +/// ``` +/// +/// # Representation +/// +/// Rust's string type, `str`, is a sequence of Unicode scalar values encoded as +/// a stream of UTF-8 bytes. All [strings](../../reference.html#literals) are +/// guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are +/// not null-terminated and can thus contain null bytes. +/// +/// The actual representation of `str`s have direct mappings to slices: `&str` +/// is the same as `&[u8]`. +/// +/// *[See also the `std::str` module](str/index.html).* +/// +mod prim_str { } + +#[doc(primitive = "tuple")] +// +/// A finite heterogeneous sequence, `(T, U, ..)`. +/// +/// To access the _N_-th element of a tuple one can use `N` itself +/// as a field of the tuple. +/// +/// Indexing starts from zero, so `0` returns first value, `1` +/// returns second value, and so on. In general, a tuple with _S_ +/// elements provides aforementioned fields from `0` to `S-1`. +/// +/// If every type inside a tuple implements one of the following +/// traits, then a tuple itself also implements it. +/// +/// * `Clone` +/// * `PartialEq` +/// * `Eq` +/// * `PartialOrd` +/// * `Ord` +/// * `Debug` +/// * `Default` +/// * `Hash` +/// +/// # Examples +/// +/// Accessing elements of a tuple at specified indices: +/// +/// ``` +/// let x = ("colorless", "green", "ideas", "sleep", "furiously"); +/// assert_eq!(x.3, "sleep"); +/// +/// let v = (3, 3); +/// let u = (1, -5); +/// assert_eq!(v.0 * u.0 + v.1 * u.1, -12); +/// ``` +/// +/// Using traits implemented for tuples: +/// +/// ``` +/// let a = (1, 2); +/// let b = (3, 4); +/// assert!(a != b); +/// +/// let c = b.clone(); +/// assert!(b == c); +/// +/// let d : (u32, f32) = Default::default(); +/// assert_eq!(d, (0, 0.0f32)); +/// ``` +/// +mod prim_tuple { } + +#[doc(primitive = "f32")] +/// The 32-bit floating point type. +/// +/// *[See also the `std::f32` module](f32/index.html).* +/// +mod prim_f32 { } + +#[doc(primitive = "f64")] +// +/// The 64-bit floating point type. +/// +/// *[See also the `std::f64` module](f64/index.html).* +/// +mod prim_f64 { } + +#[doc(primitive = "i8")] +// +/// The 8-bit signed integer type. +/// +/// *[See also the `std::i8` module](i8/index.html).* +/// +mod prim_i8 { } + +#[doc(primitive = "i16")] +// +/// The 16-bit signed integer type. +/// +/// *[See also the `std::i16` module](i16/index.html).* +/// +mod prim_i16 { } + +#[doc(primitive = "i32")] +// +/// The 32-bit signed integer type. +/// +/// *[See also the `std::i32` module](i32/index.html).* +/// +mod prim_i32 { } + +#[doc(primitive = "i64")] +// +/// The 64-bit signed integer type. +/// +/// *[See also the `std::i64` module](i64/index.html).* +/// +mod prim_i64 { } + +#[doc(primitive = "u8")] +// +/// The 8-bit unsigned integer type. +/// +/// *[See also the `std::u8` module](u8/index.html).* +/// +mod prim_u8 { } + +#[doc(primitive = "u16")] +// +/// The 16-bit unsigned integer type. +/// +/// *[See also the `std::u16` module](u16/index.html).* +/// +mod prim_u16 { } + +#[doc(primitive = "u32")] +// +/// The 32-bit unsigned integer type. +/// +/// *[See also the `std::u32` module](u32/index.html).* +/// +mod prim_u32 { } + +#[doc(primitive = "u64")] +// +/// The 64-bit unsigned integer type. +/// +/// *[See also the `std::u64` module](u64/index.html).* +/// +mod prim_u64 { } + +#[doc(primitive = "isize")] +// +/// The pointer-sized signed integer type. +/// +/// *[See also the `std::isize` module](isize/index.html).* +/// +mod prim_isize { } + +#[doc(primitive = "usize")] +// +/// The pointer-sized signed integer type. +/// +/// *[See also the `std::usize` module](usize/index.html).* +/// +mod prim_usize { } + diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a8127b3200f36..3471805b2bce1 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -23,7 +23,7 @@ use path; use sync::mpsc::{channel, Receiver}; use sys::pipe::{self, AnonPipe}; use sys::process as imp; -use sys_common::{AsInner, AsInnerMut, FromInner}; +use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use thread; /// Representation of a running or exited child process. @@ -71,6 +71,10 @@ impl AsInner for Child { fn as_inner(&self) -> &imp::Process { &self.handle } } +impl IntoInner for Child { + fn into_inner(self) -> imp::Process { self.handle } +} + /// A handle to a child procesess's stdin #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdin { @@ -92,6 +96,10 @@ impl AsInner for ChildStdin { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner for ChildStdin { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// A handle to a child procesess's stdout #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdout { @@ -109,6 +117,10 @@ impl AsInner for ChildStdout { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner for ChildStdout { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// A handle to a child procesess's stderr #[stable(feature = "process", since = "1.0.0")] pub struct ChildStderr { @@ -126,6 +138,10 @@ impl AsInner for ChildStderr { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner for ChildStderr { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// The `Command` type acts as a process builder, providing fine-grained control /// over how a new process should be spawned. A default configuration can be /// generated using `Command::new(program)`, where `program` gives a path to the diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 1729d20da205c..0ac0d03e19d40 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -96,7 +96,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // own fault handlers if we hit it. sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); - sys::thread::guard::init(); + let main_guard = sys::thread::guard::init(); sys::stack_overflow::init(); // Next, set up the current Thread with the guard information we just @@ -104,7 +104,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // but we just do this to name the main thread and to give it correct // info about the stack bounds. let thread: Thread = NewThread::new(Some("
    ".to_string())); - thread_info::set(sys::thread::guard::main(), thread); + thread_info::set(main_guard, thread); // By default, some platforms will send a *signal* when a EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs index 84c6d6864a9e5..87941e79b2f7d 100644 --- a/src/libstd/rt/unwind/gcc.rs +++ b/src/libstd/rt/unwind/gcc.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(private_no_mangle_fns)] + use prelude::v1::*; use any::Any; -use libc::c_void; use rt::libunwind as uw; struct Exception { @@ -41,7 +42,7 @@ pub unsafe fn panic(data: Box) -> ! { } } -pub unsafe fn cleanup(ptr: *mut c_void) -> Box { +pub unsafe fn cleanup(ptr: *mut u8) -> Box { let my_ep = ptr as *mut Exception; rtdebug!("caught {}", (*my_ep).uwe.exception_class); let cause = (*my_ep).cause.take(); @@ -89,7 +90,7 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_v0(version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -98,9 +99,8 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] + #[lang = "eh_personality"] + #[no_mangle] extern fn rust_eh_personality( version: c_int, actions: uw::_Unwind_Action, @@ -115,8 +115,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, @@ -142,7 +143,7 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_sj0(version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -151,9 +152,9 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + pub extern fn rust_eh_personality( version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -167,8 +168,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, @@ -196,17 +198,16 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_v0(state: uw::_Unwind_State, ue_header: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context) -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] - extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + extern fn rust_eh_personality( state: uw::_Unwind_State, ue_header: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context @@ -217,8 +218,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( state: uw::_Unwind_State, _ue_header: *mut uw::_Unwind_Exception, _context: *mut uw::_Unwind_Context @@ -266,7 +268,7 @@ pub mod eabi { } type _Unwind_Personality_Fn = - extern "C" fn( + extern fn( version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -274,7 +276,7 @@ pub mod eabi { context: *mut uw::_Unwind_Context ) -> uw::_Unwind_Reason_Code; - extern "C" { + extern { fn __gcc_personality_seh0( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, @@ -291,10 +293,9 @@ pub mod eabi { ) -> EXCEPTION_DISPOSITION; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] - extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + extern fn rust_eh_personality( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, contextRecord: *mut CONTEXT, @@ -307,15 +308,16 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, contextRecord: *mut CONTEXT, dispatcherContext: *mut DISPATCHER_CONTEXT ) -> EXCEPTION_DISPOSITION { - extern "C" fn inner( + extern fn inner( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/rt/unwind/mod.rs index c403976745aa4..db2310ba361b3 100644 --- a/src/libstd/rt/unwind/mod.rs +++ b/src/libstd/rt/unwind/mod.rs @@ -69,7 +69,6 @@ use cmp; use panicking; use fmt; use intrinsics; -use libc::c_void; use mem; use sync::atomic::{self, Ordering}; use sys_common::mutex::Mutex; @@ -127,7 +126,7 @@ extern {} /// run. pub unsafe fn try(f: F) -> Result<(), Box> { let mut f = Some(f); - return inner_try(try_fn::, &mut f as *mut _ as *mut c_void); + return inner_try(try_fn::, &mut f as *mut _ as *mut u8); // If an inner function were not used here, then this generic function `try` // uses the native symbol `rust_try`, for which the code is statically @@ -140,11 +139,12 @@ pub unsafe fn try(f: F) -> Result<(), Box> { // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll` // files and instead just have this non-generic shim the compiler can take // care of exposing correctly. - unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void) + #[cfg(not(stage0))] + unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) -> Result<(), Box> { let prev = PANICKING.with(|s| s.get()); PANICKING.with(|s| s.set(false)); - let ep = rust_try(f, data); + let ep = intrinsics::try(f, data); PANICKING.with(|s| s.set(prev)); if ep.is_null() { Ok(()) @@ -152,8 +152,13 @@ pub unsafe fn try(f: F) -> Result<(), Box> { Err(imp::cleanup(ep)) } } + #[cfg(stage0)] + unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) + -> Result<(), Box> { + Ok(f(data)) + } - extern fn try_fn(opt_closure: *mut c_void) { + fn try_fn(opt_closure: *mut u8) { let opt_closure = opt_closure as *mut Option; unsafe { (*opt_closure).take().unwrap()(); } } @@ -163,8 +168,8 @@ pub unsafe fn try(f: F) -> Result<(), Box> { // When f(...) returns normally, the return value is null. // When f(...) throws, the return value is a pointer to the caught // exception object. - fn rust_try(f: extern fn(*mut c_void), - data: *mut c_void) -> *mut c_void; + fn rust_try(f: extern fn(*mut u8), + data: *mut u8) -> *mut u8; } } diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/rt/unwind/seh.rs index 632ab4f8e2537..ed44f9a8bda94 100644 --- a/src/libstd/rt/unwind/seh.rs +++ b/src/libstd/rt/unwind/seh.rs @@ -102,7 +102,7 @@ pub unsafe fn panic(data: Box) -> ! { rtabort!("could not unwind stack"); } -pub unsafe fn cleanup(ptr: *mut c_void) -> Box { +pub unsafe fn cleanup(ptr: *mut u8) -> Box { // The `ptr` here actually corresponds to the code of the exception, and our // real data is stored in our thread local. rtassert!(ptr as DWORD == RUST_PANIC); @@ -135,8 +135,9 @@ fn rust_eh_personality() { // to ensure that it's code is RUST_PANIC, which was set by the call to // `RaiseException` above in the `panic` function. #[no_mangle] +#[lang = "msvc_try_filter"] pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS, - _rbp: *mut c_void) -> i32 { + _rbp: *mut u8) -> i32 { unsafe { ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32 } diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 5890e6a78892c..6dd222b8f6e4d 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -184,6 +184,8 @@ impl TcpStream { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) @@ -336,6 +338,8 @@ impl TcpListener { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) @@ -396,6 +400,8 @@ impl UdpSocket { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index ae55bae37aa88..bb47c946e4993 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -18,7 +18,7 @@ use thread::Thread; use thread::LocalKeyState; struct ThreadInfo { - stack_guard: usize, + stack_guard: Option, thread: Thread, } @@ -33,7 +33,7 @@ impl ThreadInfo { THREAD_INFO.with(move |c| { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { - stack_guard: 0, + stack_guard: None, thread: NewThread::new(None), }) } @@ -47,10 +47,10 @@ pub fn current_thread() -> Option { } pub fn stack_guard() -> Option { - ThreadInfo::with(|info| info.stack_guard) + ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) } -pub fn set(stack_guard: usize, thread: Thread) { +pub fn set(stack_guard: Option, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ stack_guard: stack_guard, diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 79e59ddab5be5..580d2dbcf7425 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -16,7 +16,7 @@ use fs; use net; use os::raw; use sys; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -59,6 +59,18 @@ pub trait FromRawFd { unsafe fn from_raw_fd(fd: RawFd) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -71,6 +83,11 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } +impl IntoRawFd for fs::File { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::TcpStream { @@ -106,3 +123,19 @@ impl FromRawFd for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) } } + +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index cfe7a1f2dda0d..63adae17581a2 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -13,11 +13,11 @@ #![stable(feature = "rust1", since = "1.0.0")] use os::unix::raw::{uid_t, gid_t}; -use os::unix::io::{FromRawFd, RawFd, AsRawFd}; +use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; use prelude::v1::*; use process; use sys; -use sys_common::{AsInnerMut, AsInner, FromInner}; +use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; /// Unix-specific extensions to the `std::process::Command` builder #[stable(feature = "rust1", since = "1.0.0")] @@ -92,3 +92,21 @@ impl AsRawFd for process::ChildStderr { self.as_inner().fd().raw() } } + +impl IntoRawFd for process::ChildStdin { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStdout { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStderr { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 867cdcbab94cb..0c99a30f107d0 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -331,6 +331,8 @@ impl File { } pub fn fd(&self) -> &FileDesc { &self.0 } + + pub fn into_fd(self) -> FileDesc { self.0 } } impl DirBuilder { diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 1f40c18be2f10..37eb7fd2ac803 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -17,7 +17,7 @@ use str; use sys::c; use net::SocketAddr; use sys::fd::FileDesc; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{getsockopt, setsockopt}; use time::Duration; @@ -127,3 +127,7 @@ impl AsInner for Socket { impl FromInner for Socket { fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) } } + +impl IntoInner for Socket { + fn into_inner(self) -> c_int { self.0.into_raw() } +} diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 946857c05bc4a..140f0c042ba8f 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -46,4 +46,5 @@ impl AnonPipe { pub fn raw(&self) -> libc::c_int { self.0.raw() } pub fn fd(&self) -> &FileDesc { &self.0 } + pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 17804c8d81ffb..6be61f069266f 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -166,9 +166,10 @@ impl Drop for Thread { not(target_os = "netbsd"), not(target_os = "openbsd")))] pub mod guard { - pub unsafe fn current() -> usize { 0 } - pub unsafe fn main() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } @@ -179,6 +180,8 @@ pub mod guard { target_os = "openbsd"))] #[allow(unused_imports)] pub mod guard { + use prelude::v1::*; + use libc::{self, pthread_t}; use libc::funcs::posix88::mman::mmap; use libc::consts::os::posix88::{PROT_NONE, @@ -191,31 +194,38 @@ pub mod guard { use super::{pthread_self, pthread_attr_destroy}; use sys::os; - // These are initialized in init() and only read from after - static mut GUARD_PAGE: usize = 0; - #[cfg(any(target_os = "macos", target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] - unsafe fn get_stack_start() -> *mut libc::c_void { - current() as *mut libc::c_void + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + current().map(|s| s as *mut libc::c_void) } #[cfg(any(target_os = "linux", target_os = "android"))] - unsafe fn get_stack_start() -> *mut libc::c_void { + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut stackaddr = ptr::null_mut(); - let mut stacksize = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut stackaddr = ptr::null_mut(); + let mut stacksize = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, + &mut stacksize), 0); + ret = Some(stackaddr); + } assert_eq!(pthread_attr_destroy(&mut attr), 0); - stackaddr + ret } - pub unsafe fn init() { + pub unsafe fn init() -> Option { let psize = os::page_size(); - let mut stackaddr = get_stack_start(); + let mut stackaddr = match get_stack_start() { + Some(addr) => addr, + None => return None, + }; // Ensure stackaddr is page aligned! A parent process might // have reset RLIMIT_STACK to be non-page aligned. The @@ -245,25 +255,21 @@ pub mod guard { let offset = if cfg!(target_os = "linux") {2} else {1}; - GUARD_PAGE = stackaddr as usize + offset * psize; - } - - pub unsafe fn main() -> usize { - GUARD_PAGE + Some(stackaddr as usize + offset * psize) } #[cfg(target_os = "macos")] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option { extern { fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void; fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t; } - (pthread_get_stackaddr_np(pthread_self()) as libc::size_t - - pthread_get_stacksize_np(pthread_self())) as usize + Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t - + pthread_get_stacksize_np(pthread_self())) as usize) } #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option { #[repr(C)] struct stack_t { ss_sp: *mut libc::c_void, @@ -280,30 +286,36 @@ pub mod guard { assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0); let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); - if pthread_main_np() == 1 { + Some(if pthread_main_np() == 1 { // main thread current_stack.ss_sp as usize - current_stack.ss_size as usize + extra } else { // new thread current_stack.ss_sp as usize - current_stack.ss_size as usize - } + }) } #[cfg(any(target_os = "linux", target_os = "android"))] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut guardsize = 0; - assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); - if guardsize == 0 { - panic!("there is no guard page"); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut guardsize = 0; + assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); + if guardsize == 0 { + panic!("there is no guard page"); + } + let mut stackaddr = ptr::null_mut(); + let mut size = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); + + ret = Some(stackaddr as usize + guardsize as usize); } - let mut stackaddr = ptr::null_mut(); - let mut size = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); assert_eq!(pthread_attr_destroy(&mut attr), 0); - - stackaddr as usize + guardsize as usize + return ret } #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs index f4717eb2425e1..185f1abe64b9a 100644 --- a/src/libstd/sys/windows/ext/io.rs +++ b/src/libstd/sys/windows/ext/io.rs @@ -13,7 +13,7 @@ use fs; use os::windows::raw; use net; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; use sys; /// Raw HANDLEs. @@ -50,6 +50,18 @@ pub trait FromRawHandle { unsafe fn from_raw_handle(handle: RawHandle) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `HANDLE`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawHandle { + /// Consumes this object, returning the raw underlying handle. + /// + /// This function **transfers ownership** of the underlying handle to the + /// caller. Callers are then the unique owners of the handle and must close + /// it once it's no longer needed. + fn into_raw_handle(self) -> RawHandle; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawHandle for fs::File { fn as_raw_handle(&self) -> RawHandle { @@ -65,6 +77,12 @@ impl FromRawHandle for fs::File { } } +impl IntoRawHandle for fs::File { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + /// Extract raw sockets. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawSocket { @@ -90,6 +108,18 @@ pub trait FromRawSocket { unsafe fn from_raw_socket(sock: RawSocket) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `SOCKET`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawSocket { + /// Consumes this object, returning the raw underlying socket. + /// + /// This function **transfers ownership** of the underlying socket to the + /// caller. Callers are then the unique owners of the socket and must close + /// it once it's no longer needed. + fn into_raw_socket(self) -> RawSocket; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpStream { fn as_raw_socket(&self) -> RawSocket { @@ -130,3 +160,21 @@ impl FromRawSocket for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) } } + +impl IntoRawSocket for net::TcpStream { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::TcpListener { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::UdpSocket { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 6f59be2687a1b..fde21e9a798ee 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -12,10 +12,10 @@ #![stable(feature = "process_extensions", since = "1.2.0")] -use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle}; +use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; use process; use sys; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { @@ -32,6 +32,12 @@ impl AsRawHandle for process::Child { } } +impl IntoRawHandle for process::Child { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdin { fn as_raw_handle(&self) -> RawHandle { @@ -52,3 +58,21 @@ impl AsRawHandle for process::ChildStderr { self.as_inner().handle().raw() as *mut _ } } + +impl IntoRawHandle for process::ChildStdin { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStdout { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStderr { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 890cc455d5df2..4ce6d53cf125c 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -319,6 +319,8 @@ impl File { pub fn handle(&self) -> &Handle { &self.handle } + pub fn into_handle(self) -> Handle { self.handle } + fn reparse_point<'a>(&self, space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]) -> io::Result<(libc::DWORD, &'a c::REPARSE_DATA_BUFFER)> { @@ -357,8 +359,6 @@ impl File { Ok(PathBuf::from(OsString::from_wide(subst))) } } - - pub fn into_handle(self) -> Handle { self.handle } } impl FromInner for File { @@ -369,10 +369,13 @@ impl FromInner for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME(#24570): add more info here (e.g. path, mode) - f.debug_struct("File") - .field("handle", &self.handle.raw()) - .finish() + // FIXME(#24570): add more info here (e.g. mode) + let mut b = f.debug_struct("File"); + b.field("handle", &self.handle.raw()); + if let Ok(path) = get_path(&self) { + b.field("path", &path); + } + b.finish() } } @@ -582,11 +585,7 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { Ok(()) } -pub fn canonicalize(p: &Path) -> io::Result { - - let mut opts = OpenOptions::new(); - opts.read(true); - let f = try!(File::open(p, &opts)); +fn get_path(f: &File) -> io::Result { super::fill_utf16_buf(|buf, sz| unsafe { c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, libc::VOLUME_NAME_DOS) @@ -595,6 +594,13 @@ pub fn canonicalize(p: &Path) -> io::Result { }) } +pub fn canonicalize(p: &Path) -> io::Result { + let mut opts = OpenOptions::new(); + opts.read(true); + let f = try!(File::open(p, &opts)); + get_path(&f) +} + pub fn copy(from: &Path, to: &Path) -> io::Result { unsafe extern "system" fn callback( _TotalFileSize: libc::LARGE_INTEGER, diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index b765bc6e50085..d58355ed1feef 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -21,7 +21,7 @@ use rt; use sync::Once; use sys; use sys::c; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{setsockopt, getsockopt}; use time::Duration; @@ -184,3 +184,11 @@ impl AsInner for Socket { impl FromInner for Socket { fn from_inner(sock: libc::SOCKET) -> Socket { Socket(sock) } } + +impl IntoInner for Socket { + fn into_inner(self) -> libc::SOCKET { + let ret = self.0; + mem::forget(self); + ret + } +} diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index b2a6607314a50..a7ece66e0f1f7 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -37,6 +37,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { impl AnonPipe { pub fn handle(&self) -> &Handle { &self.inner } + pub fn into_handle(self) -> Handle { self.inner } pub fn raw(&self) -> libc::HANDLE { self.inner.raw() } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 0b0268d4746ab..ca33e11eea059 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -220,6 +220,8 @@ impl Process { } pub fn handle(&self) -> &Handle { &self.handle } + + pub fn into_handle(self) -> Handle { self.handle } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 50dfee4ab1011..42805c2ac52c4 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -86,7 +86,8 @@ impl Thread { } pub mod guard { - pub unsafe fn main() -> usize { 0 } - pub unsafe fn current() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index a2dbb0f834243..7550b7ce6c352 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -231,9 +231,12 @@ pub static p_thread_callback: unsafe extern "system" fn(LPVOID, DWORD, LPVOID) = on_tls_callback; -#[cfg(target_env = "msvc")] +#[cfg(all(target_env = "msvc", target_pointer_width = "64"))] #[link_args = "/INCLUDE:_tls_used"] extern {} +#[cfg(all(target_env = "msvc", target_pointer_width = "32"))] +#[link_args = "/INCLUDE:__tls_used"] +extern {} #[allow(warnings)] unsafe extern "system" fn on_tls_callback(h: LPVOID, diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index dbb7d3233bc39..3299c848ba724 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -508,9 +508,25 @@ pub fn sleep(dur: Duration) { imp::Thread::sleep(dur) } -/// Blocks unless or until the current thread's token is made available (may wake spuriously). +/// Blocks unless or until the current thread's token is made available. /// -/// See the module doc for more detail. +/// Every thread is equipped with some basic low-level blocking support, via +/// the `park()` function and the [`unpark()`][unpark] method. These can be +/// used as a more CPU-efficient implementation of a spinlock. +/// +/// [unpark]: struct.Thread.html#method.unpark +/// +/// The API is typically used by acquiring a handle to the current thread, +/// placing that handle in a shared data structure so that other threads can +/// find it, and then parking (in a loop with a check for the token actually +/// being acquired). +/// +/// A call to `park` does not guarantee that the thread will remain parked +/// forever, and callers should be prepared for this possibility. +/// +/// See the [module documentation][thread] for more detail. +/// +/// [thread]: index.html // // The implementation currently uses the trivial strategy of a Mutex+Condvar // with wakeup flag, which does not actually allow spurious wakeups. In the diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs deleted file mode 100644 index 08aa979cf631f..0000000000000 --- a/src/libstd/tuple.rs +++ /dev/null @@ -1,60 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations on tuples -//! -//! To access the _N_-th element of a tuple one can use `N` itself -//! as a field of the tuple. -//! -//! Indexing starts from zero, so `0` returns first value, `1` -//! returns second value, and so on. In general, a tuple with _S_ -//! elements provides aforementioned fields from `0` to `S-1`. -//! -//! If every type inside a tuple implements one of the following -//! traits, then a tuple itself also implements it. -//! -//! * `Clone` -//! * `PartialEq` -//! * `Eq` -//! * `PartialOrd` -//! * `Ord` -//! * `Debug` -//! * `Default` -//! * `Hash` -//! -//! # Examples -//! -//! Accessing elements of a tuple at specified indices: -//! -//! ``` -//! let x = ("colorless", "green", "ideas", "sleep", "furiously"); -//! assert_eq!(x.3, "sleep"); -//! -//! let v = (3, 3); -//! let u = (1, -5); -//! assert_eq!(v.0 * u.0 + v.1 * u.1, -12); -//! ``` -//! -//! Using traits implemented for tuples: -//! -//! ``` -//! let a = (1, 2); -//! let b = (3, 4); -//! assert!(a != b); -//! -//! let c = b.clone(); -//! assert!(b == c); -//! -//! let d : (u32, f32) = Default::default(); -//! assert_eq!(d, (0, 0.0f32)); -//! ``` - -#![doc(primitive = "tuple")] -#![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/unit.rs b/src/libstd/unit.rs deleted file mode 100644 index 2c3ddcd9d4947..0000000000000 --- a/src/libstd/unit.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![doc(primitive = "unit")] -#![stable(feature = "rust1", since = "1.0.0")] - -//! The `()` type, sometimes called "unit" or "nil". -//! -//! The `()` type has exactly one value `()`, and is used when there -//! is no other meaningful value that could be returned. `()` is most -//! commonly seen implicitly: functions without a `-> ...` implicitly -//! have return type `()`, that is, these are equivalent: -//! -//! ```rust -//! fn long() -> () {} -//! -//! fn short() {} -//! ``` -//! -//! The semicolon `;` can be used to discard the result of an -//! expression at the end of a block, making the expression (and thus -//! the block) evaluate to `()`. For example, -//! -//! ```rust -//! fn returns_i64() -> i64 { -//! 1i64 -//! } -//! fn returns_unit() { -//! 1i64; -//! } -//! -//! let is_i64 = { -//! returns_i64() -//! }; -//! let is_unit = { -//! returns_i64(); -//! }; -//! ``` diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a944acad84df1..a0059d33bed84 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -63,6 +63,7 @@ use owned_slice::OwnedSlice; use parse::token::{InternedString, str_to_ident}; use parse::token; use parse::lexer; +use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use print::pprust; use ptr::P; @@ -1079,7 +1080,12 @@ pub enum TokenTree { impl TokenTree { pub fn len(&self) -> usize { match *self { - TtToken(_, token::DocComment(_)) => 2, + TtToken(_, token::DocComment(name)) => { + match doc_comment_style(name.as_str()) { + AttrOuter => 2, + AttrInner => 3 + } + } TtToken(_, token::SpecialVarNt(..)) => 2, TtToken(_, token::MatchNt(..)) => 3, TtDelimited(_, ref delimed) => { @@ -1097,14 +1103,20 @@ impl TokenTree { (&TtToken(sp, token::DocComment(_)), 0) => { TtToken(sp, token::Pound) } - (&TtToken(sp, token::DocComment(name)), 1) => { + (&TtToken(sp, token::DocComment(name)), 1) + if doc_comment_style(name.as_str()) == AttrInner => { + TtToken(sp, token::Not) + } + (&TtToken(sp, token::DocComment(name)), _) => { + let stripped = strip_doc_comment_decoration(name.as_str()); TtDelimited(sp, Rc::new(Delimited { delim: token::Bracket, open_span: sp, tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::Literal(token::StrRaw(name, 0), None))], + TtToken(sp, token::Literal( + token::StrRaw(token::intern(&stripped), 0), None))], close_span: sp, })) } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5ddcfaef9ea28..e6bc3218897d9 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -115,6 +115,10 @@ impl Sub for CharPos { /// are *absolute* positions from the beginning of the codemap, not positions /// relative to FileMaps. Methods on the CodeMap can be used to relate spans back /// to the original source. +/// You must be careful if the span crosses more than one file - you will not be +/// able to use many of the functions on spans in codemap and you cannot assume +/// that the length of the span = hi - lo; there may be space in the BytePos +/// range between files. #[derive(Clone, Copy, Hash)] pub struct Span { pub lo: BytePos, @@ -339,7 +343,7 @@ pub struct MultiByteChar { pub bytes: usize, } -/// A single source in the CodeMap +/// A single source in the CodeMap. pub struct FileMap { /// The name of the file that the source came from, source that doesn't /// originate from files has names between angle brackets by convention, @@ -508,6 +512,9 @@ impl FileMap { lines.get(line_number).map(|&line| { let begin: BytePos = line - self.start_pos; let begin = begin.to_usize(); + // We can't use `lines.get(line_number+1)` because we might + // be parsing when we call this function and thus the current + // line is the last one we have line info for. let slice = &src[begin..]; match slice.find('\n') { Some(e) => &slice[..e], @@ -598,27 +605,27 @@ impl CodeMap { Ok(self.new_filemap(path.to_str().unwrap().to_string(), src)) } + fn next_start_pos(&self) -> usize { + let files = self.files.borrow(); + match files.last() { + None => 0, + // Add one so there is some space between files. This lets us distinguish + // positions in the codemap, even in the presence of zero-length files. + Some(last) => last.end_pos.to_usize() + 1, + } + } + + /// Creates a new filemap without setting its line information. If you don't + /// intend to set the line information yourself, you should use new_filemap_and_lines. pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc { + let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); - let start_pos = match files.last() { - None => 0, - Some(last) => last.end_pos.to_usize(), - }; // Remove utf-8 BOM if any. if src.starts_with("\u{feff}") { src.drain(..3); } - // Append '\n' in case it's not already there. - // This is a workaround to prevent CodeMap.lookup_filemap_idx from - // accidentally overflowing into the next filemap in case the last byte - // of span is also the last byte of filemap, which leads to incorrect - // results from CodeMap.span_to_*. - if !src.is_empty() && !src.ends_with("\n") { - src.push('\n'); - } - let end_pos = start_pos + src.len(); let filemap = Rc::new(FileMap { @@ -635,6 +642,21 @@ impl CodeMap { filemap } + /// Creates a new filemap and sets its line information. + pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc { + let fm = self.new_filemap(filename.to_string(), src.to_owned()); + let mut byte_pos: u32 = 0; + for line in src.lines() { + // register the start of this line + fm.next_line(BytePos(byte_pos)); + + // update byte_pos to include this line and the \n at the end + byte_pos += line.len() as u32 + 1; + } + fm + } + + /// Allocates a new FileMap representing a source file from an external /// crate. The source code of such an "imported filemap" is not available, /// but we still know enough to generate accurate debuginfo location @@ -645,11 +667,8 @@ impl CodeMap { mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec) -> Rc { + let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); - let start_pos = match files.last() { - None => 0, - Some(last) => last.end_pos.to_usize(), - }; let end_pos = Pos::from_usize(start_pos + source_len); let start_pos = Pos::from_usize(start_pos); @@ -686,39 +705,61 @@ impl CodeMap { /// Lookup source information about a BytePos pub fn lookup_char_pos(&self, pos: BytePos) -> Loc { - let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos); - let line = a + 1; // Line numbers start at 1 let chpos = self.bytepos_to_file_charpos(pos); - let linebpos = (*f.lines.borrow())[a]; - let linechpos = self.bytepos_to_file_charpos(linebpos); - debug!("byte pos {:?} is on the line at byte pos {:?}", - pos, linebpos); - debug!("char pos {:?} is on the line at char pos {:?}", - chpos, linechpos); - debug!("byte is on line: {}", line); - assert!(chpos >= linechpos); - Loc { - file: f, - line: line, - col: chpos - linechpos + match self.lookup_line(pos) { + Ok(FileMapAndLine { fm: f, line: a }) => { + let line = a + 1; // Line numbers start at 1 + let linebpos = (*f.lines.borrow())[a]; + let linechpos = self.bytepos_to_file_charpos(linebpos); + debug!("byte pos {:?} is on the line at byte pos {:?}", + pos, linebpos); + debug!("char pos {:?} is on the line at char pos {:?}", + chpos, linechpos); + debug!("byte is on line: {}", line); + assert!(chpos >= linechpos); + Loc { + file: f, + line: line, + col: chpos - linechpos, + } + } + Err(f) => { + Loc { + file: f, + line: 0, + col: chpos, + } + } } } - fn lookup_line(&self, pos: BytePos) -> FileMapAndLine { + // If the relevant filemap is empty, we don't return a line number. + fn lookup_line(&self, pos: BytePos) -> Result> { let idx = self.lookup_filemap_idx(pos); let files = self.files.borrow(); let f = (*files)[idx].clone(); + + let len = f.lines.borrow().len(); + if len == 0 { + return Err(f); + } + let mut a = 0; { let lines = f.lines.borrow(); let mut b = lines.len(); while b - a > 1 { let m = (a + b) / 2; - if (*lines)[m] > pos { b = m; } else { a = m; } + if (*lines)[m] > pos { + b = m; + } else { + a = m; + } } + assert!(a <= lines.len()); } - FileMapAndLine {fm: f, line: a} + Ok(FileMapAndLine { fm: f, line: a }) } pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt { @@ -853,7 +894,7 @@ impl CodeMap { FileMapAndBytePos {fm: fm, pos: offset} } - /// Converts an absolute BytePos to a CharPos relative to the filemap and above. + /// Converts an absolute BytePos to a CharPos relative to the filemap. pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { let idx = self.lookup_filemap_idx(bpos); let files = self.files.borrow(); @@ -880,12 +921,15 @@ impl CodeMap { CharPos(bpos.to_usize() - map.start_pos.to_usize() - total_extra_bytes) } + // Return the index of the filemap (in self.files) which contains pos. fn lookup_filemap_idx(&self, pos: BytePos) -> usize { let files = self.files.borrow(); let files = &*files; - let len = files.len(); + let count = files.len(); + + // Binary search for the filemap. let mut a = 0; - let mut b = len; + let mut b = count; while b - a > 1 { let m = (a + b) / 2; if files[m].start_pos > pos { @@ -894,26 +938,8 @@ impl CodeMap { a = m; } } - // There can be filemaps with length 0. These have the same start_pos as - // the previous filemap, but are not the filemaps we want (because they - // are length 0, they cannot contain what we are looking for). So, - // rewind until we find a useful filemap. - loop { - let lines = files[a].lines.borrow(); - let lines = lines; - if !lines.is_empty() { - break; - } - if a == 0 { - panic!("position {} does not resolve to a source location", - pos.to_usize()); - } - a -= 1; - } - if a >= len { - panic!("position {} does not resolve to a source location", - pos.to_usize()) - } + + assert!(a < count, "position {} does not resolve to a source location", pos.to_usize()); return a; } @@ -1027,10 +1053,13 @@ mod tests { let fm = cm.new_filemap("blork.rs".to_string(), "first line.\nsecond line".to_string()); fm.next_line(BytePos(0)); + // Test we can get lines with partial line info. assert_eq!(fm.get_line(0), Some("first line.")); - // TESTING BROKEN BEHAVIOR: + // TESTING BROKEN BEHAVIOR: line break declared before actual line break. fm.next_line(BytePos(10)); assert_eq!(fm.get_line(1), Some(".")); + fm.next_line(BytePos(12)); + assert_eq!(fm.get_line(2), Some("second line")); } #[test] @@ -1056,9 +1085,9 @@ mod tests { fm1.next_line(BytePos(0)); fm1.next_line(BytePos(12)); - fm2.next_line(BytePos(24)); - fm3.next_line(BytePos(24)); - fm3.next_line(BytePos(34)); + fm2.next_line(fm2.start_pos); + fm3.next_line(fm3.start_pos); + fm3.next_line(fm3.start_pos + BytePos(12)); cm } @@ -1068,11 +1097,15 @@ mod tests { // Test lookup_byte_offset let cm = init_code_map(); - let fmabp1 = cm.lookup_byte_offset(BytePos(22)); + let fmabp1 = cm.lookup_byte_offset(BytePos(23)); assert_eq!(fmabp1.fm.name, "blork.rs"); - assert_eq!(fmabp1.pos, BytePos(22)); + assert_eq!(fmabp1.pos, BytePos(23)); + + let fmabp1 = cm.lookup_byte_offset(BytePos(24)); + assert_eq!(fmabp1.fm.name, "empty.rs"); + assert_eq!(fmabp1.pos, BytePos(0)); - let fmabp2 = cm.lookup_byte_offset(BytePos(24)); + let fmabp2 = cm.lookup_byte_offset(BytePos(25)); assert_eq!(fmabp2.fm.name, "blork2.rs"); assert_eq!(fmabp2.pos, BytePos(0)); } @@ -1085,7 +1118,7 @@ mod tests { let cp1 = cm.bytepos_to_file_charpos(BytePos(22)); assert_eq!(cp1, CharPos(22)); - let cp2 = cm.bytepos_to_file_charpos(BytePos(24)); + let cp2 = cm.bytepos_to_file_charpos(BytePos(25)); assert_eq!(cp2, CharPos(0)); } @@ -1099,7 +1132,7 @@ mod tests { assert_eq!(loc1.line, 2); assert_eq!(loc1.col, CharPos(10)); - let loc2 = cm.lookup_char_pos(BytePos(24)); + let loc2 = cm.lookup_char_pos(BytePos(25)); assert_eq!(loc2.file.name, "blork2.rs"); assert_eq!(loc2.line, 1); assert_eq!(loc2.col, CharPos(0)); @@ -1115,18 +1148,18 @@ mod tests { "first line€€.\n€ second line".to_string()); fm1.next_line(BytePos(0)); - fm1.next_line(BytePos(22)); - fm2.next_line(BytePos(40)); - fm2.next_line(BytePos(58)); + fm1.next_line(BytePos(28)); + fm2.next_line(fm2.start_pos); + fm2.next_line(fm2.start_pos + BytePos(20)); fm1.record_multibyte_char(BytePos(3), 3); fm1.record_multibyte_char(BytePos(9), 3); fm1.record_multibyte_char(BytePos(12), 3); fm1.record_multibyte_char(BytePos(15), 3); fm1.record_multibyte_char(BytePos(18), 3); - fm2.record_multibyte_char(BytePos(50), 3); - fm2.record_multibyte_char(BytePos(53), 3); - fm2.record_multibyte_char(BytePos(58), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(10), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(13), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(18), 3); cm } @@ -1172,19 +1205,6 @@ mod tests { Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } } - fn new_filemap_and_lines(cm: &CodeMap, filename: &str, input: &str) -> Rc { - let fm = cm.new_filemap(filename.to_string(), input.to_string()); - let mut byte_pos: u32 = 0; - for line in input.lines() { - // register the start of this line - fm.next_line(BytePos(byte_pos)); - - // update byte_pos to include this line and the \n at the end - byte_pos += line.len() as u32 + 1; - } - fm - } - /// Test span_to_snippet and span_to_lines for a span coverting 3 /// lines in the middle of a file. #[test] @@ -1192,7 +1212,7 @@ mod tests { let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; let selection = " \n ^~\n~~~\n~~~~~ \n \n"; - new_filemap_and_lines(&cm, "blork.rs", inputtext); + cm.new_filemap_and_lines("blork.rs", inputtext); let span = span_from_selection(inputtext, selection); // check that we are extracting the text we thought we were extracting diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index fbf015169f858..f1d748595d6f0 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -208,6 +208,10 @@ impl Handler { } pub fn fatal(&self, msg: &str) -> ! { self.emit.borrow_mut().emit(None, msg, None, Fatal); + + // Suppress the fatal error message from the panic below as we've + // already terminated in our own "legitimate" fashion. + io::set_panic(Box::new(io::sink())); panic!(FatalError); } pub fn err(&self, msg: &str) { @@ -837,12 +841,7 @@ mod test { tolv dreizehn "; - let file = cm.new_filemap("dummy.txt".to_string(), content.to_string()); - for (i, b) in content.bytes().enumerate() { - if b == b'\n' { - file.next_line(BytePos(i as u32)); - } - } + let file = cm.new_filemap_and_lines("dummy.txt", content); let start = file.lines.borrow()[7]; let end = file.lines.borrow()[11]; let sp = mk_sp(start, end); @@ -854,11 +853,12 @@ mod test { println!("done"); let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; - println!("{}", from_utf8(vec).unwrap()); - assert_eq!(vec, "dummy.txt: 8 \n\ - dummy.txt: 9 \n\ - dummy.txt:10 \n\ - dummy.txt:11 \n\ - dummy.txt:12 \n".as_bytes()); + let str = from_utf8(vec).unwrap(); + println!("{}", str); + assert_eq!(str, "dummy.txt: 8 line8\n\ + dummy.txt: 9 line9\n\ + dummy.txt:10 line10\n\ + dummy.txt:11 e-lä-vän\n\ + dummy.txt:12 tolv\n"); } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 5418b1f43e4af..22517dc5f1bb5 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -156,7 +156,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // dependency information let filename = format!("{}", file.display()); let interned = token::intern_and_get_ident(&src[..]); - cx.codemap().new_filemap(filename, src); + cx.codemap().new_filemap_and_lines(&filename, &src); base::MacEager::expr(cx.expr_str(sp, interned)) } @@ -187,7 +187,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // Add this input file to the code map to make it available as // dependency information, but don't enter it's contents let filename = format!("{}", file.display()); - cx.codemap().new_filemap(filename, "".to_string()); + cx.codemap().new_filemap_and_lines(&filename, ""); base::MacEager::expr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 7333265bdd412..d93af5da13c1e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -32,6 +32,7 @@ #![feature(libc)] #![feature(ref_slice)] #![feature(rustc_private)] +#![feature(set_stdio)] #![feature(staged_api)] #![feature(str_char)] #![feature(str_escape)] diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b6a3788dacc34..621335ecd979c 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -231,6 +231,7 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; + self.peek_span = codemap::mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.last_pos; self.peek_tok = self.next_token_inner(); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index d6c28d4144792..34a63fc92feaa 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -11,7 +11,7 @@ //! The main parser interface use ast; -use codemap::{Span, CodeMap, FileMap}; +use codemap::{self, Span, CodeMap, FileMap}; use diagnostic::{SpanHandler, Handler, Auto, FatalError}; use parse::attr::ParserAttr; use parse::parser::Parser; @@ -203,7 +203,14 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, cfg: ast::CrateConfig) -> Parser<'a> { - tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg) + let end_pos = filemap.end_pos; + let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg); + + if parser.token == token::Eof && parser.span == codemap::DUMMY_SP { + parser.span = codemap::mk_sp(end_pos, end_pos); + } + + parser } // must preserve old name for now, because quote! from the *existing* diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 28802d323c692..db1b2489f1d9e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4824,8 +4824,14 @@ impl<'a> Parser<'a> { return Err(self.fatal(&format!("expected item, found `{}`", token_str))); } + let hi = if self.span == codemap::DUMMY_SP { + inner_lo + } else { + self.span.lo + }; + Ok(ast::Mod { - inner: mk_sp(inner_lo, self.span.lo), + inner: mk_sp(inner_lo, hi), items: items }) } @@ -4869,8 +4875,7 @@ impl<'a> Parser<'a> { fn push_mod_path(&mut self, id: Ident, attrs: &[Attribute]) { let default_path = self.id_to_interned_str(id); - let file_path = match ::attr::first_attr_value_str_by_name(attrs, - "path") { + let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") { Some(d) => d, None => default_path, }; @@ -5003,13 +5008,12 @@ impl<'a> Parser<'a> { included_mod_stack.push(path.clone()); drop(included_mod_stack); - let mut p0 = - new_sub_parser_from_file(self.sess, - self.cfg.clone(), - &path, - owns_directory, - Some(name), - id_sp); + let mut p0 = new_sub_parser_from_file(self.sess, + self.cfg.clone(), + &path, + owns_directory, + Some(name), + id_sp); let mod_inner_lo = p0.span.lo; let mod_attrs = p0.parse_inner_attributes(); let m0 = try!(p0.parse_mod_items(&token::Eof, mod_inner_lo)); diff --git a/src/rt/rust_try.ll b/src/rt/rust_try.ll deleted file mode 100644 index 8643131d0fb74..0000000000000 --- a/src/rt/rust_try.ll +++ /dev/null @@ -1,54 +0,0 @@ -; Copyright 2013 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. - -; Rust's try-catch -; When f(...) returns normally, the return value is null. -; When f(...) throws, the return value is a pointer to the caught exception object. - -; See also: libstd/rt/unwind/mod.rs - -define i8* @rust_try(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @rust_eh_personality_catch to i8*) -{ - - %1 = invoke i8* @rust_try_inner(void (i8*)* %f, i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* %1 - -catch: - landingpad { i8*, i32 } catch i8* null - ; rust_try_inner's landing pad does not resume unwinds, so execution will - ; never reach here - ret i8* null -} - -define internal i8* @rust_try_inner(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @rust_eh_personality to i8*) -{ - - invoke void %f(i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* null - -catch: - %1 = landingpad { i8*, i32 } catch i8* null - ; extract and return pointer to the exception object - %2 = extractvalue { i8*, i32 } %1, 0 - ret i8* %2 -} - -declare i32 @rust_eh_personality(...) -declare i32 @rust_eh_personality_catch(...) diff --git a/src/rt/rust_try_msvc_32.ll b/src/rt/rust_try_msvc_32.ll deleted file mode 100644 index bdee53b136e10..0000000000000 --- a/src/rt/rust_try_msvc_32.ll +++ /dev/null @@ -1,42 +0,0 @@ -; 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. - -; For more comments about what's going on here see rust_try_msvc_64.ll. The only -; difference between that and this file is the personality function used as it's -; different for 32-bit MSVC than it is for 64-bit. - -define i8* @rust_try(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -{ - invoke void %f(i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* null -catch: - %vals = landingpad { i8*, i32 } - catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*) - %ehptr = extractvalue { i8*, i32 } %vals, 0 - %sel = extractvalue { i8*, i32 } %vals, 1 - %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)) - %is_filter = icmp eq i32 %sel, %filter_sel - br i1 %is_filter, label %catch-return, label %catch-resume - -catch-return: - ret i8* %ehptr - -catch-resume: - resume { i8*, i32 } %vals -} - -declare i32 @_except_handler3(...) -declare i32 @__rust_try_filter(i8*, i8*) -declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind diff --git a/src/rt/rust_try_msvc_64.ll b/src/rt/rust_try_msvc_64.ll deleted file mode 100644 index c38e6081bf2d3..0000000000000 --- a/src/rt/rust_try_msvc_64.ll +++ /dev/null @@ -1,80 +0,0 @@ -; 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. - -; 64-bit MSVC's definition of the `rust_try` function. This function can't be -; defined in Rust as it's a "try-catch" block that's not expressible in Rust's -; syntax, so we're using LLVM to produce an object file with the associated -; handler. -; -; To use the correct system implementation details, this file is separate from -; the standard rust_try.ll as we need specifically use the __C_specific_handler -; personality function or otherwise LLVM doesn't emit SEH handling tables. -; There's also a few fiddly bits about SEH right now in LLVM that require us to -; structure this a fairly particular way! -; -; See also: src/libstd/rt/unwind/seh.rs - -define i8* @rust_try(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -{ - invoke void %f(i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* null - -; Here's where most of the magic happens, this is the only landing pad in rust -; tagged with "catch" to indicate that we're catching an exception. The other -; catch handlers in rust_try.ll just catch *all* exceptions, but that's because -; most exceptions are already filtered out by their personality function. -; -; For MSVC we're just using a standard personality function that we can't -; customize, so we need to do the exception filtering ourselves, and this is -; currently performed by the `__rust_try_filter` function. This function, -; specified in the landingpad instruction, will be invoked by Windows SEH -; routines and will return whether the exception in question can be caught (aka -; the Rust runtime is the one that threw the exception). -; -; To get this to compile (currently LLVM segfaults if it's not in this -; particular structure), when the landingpad is executing we test to make sure -; that the ID of the exception being thrown is indeed the one that we were -; expecting. If it's not, we resume the exception, and otherwise we return the -; pointer that we got -; -; Full disclosure: It's not clear to me what this `llvm.eh.typeid` stuff is -; doing *other* then just allowing LLVM to compile this file without -; segfaulting. I would expect the entire landing pad to just be: -; -; %vals = landingpad ... -; %ehptr = extractvalue { i8*, i32 } %vals, 0 -; ret i8* %ehptr -; -; but apparently LLVM chokes on this, so we do the more complicated thing to -; placate it. -catch: - %vals = landingpad { i8*, i32 } - catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*) - %ehptr = extractvalue { i8*, i32 } %vals, 0 - %sel = extractvalue { i8*, i32 } %vals, 1 - %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)) - %is_filter = icmp eq i32 %sel, %filter_sel - br i1 %is_filter, label %catch-return, label %catch-resume - -catch-return: - ret i8* %ehptr - -catch-resume: - resume { i8*, i32 } %vals -} - -declare i32 @__C_specific_handler(...) -declare i32 @__rust_try_filter(i8*, i8*) -declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 163e95b890f4b..5007af0e777b8 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -120,7 +120,8 @@ extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, B))); } -extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) { +extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, + uint64_t Val) { Function *A = unwrap(Fn); AttrBuilder B; B.addRawValue(Val); diff --git a/src/snapshots.txt b/src/snapshots.txt index 1b2613d8c5045..cb5790b34f4d3 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2015-07-17 d4432b3 + linux-i386 93f6216a35d3bed3cedf244c9aff4cd716336bd9 + linux-x86_64 d8f4967fc71a153c925faecf95a7feadf7e463a4 + macos-i386 29852c4d4b5a851f16d627856a279cae5bf9bd01 + macos-x86_64 1a20259899321062a0325edb1d22990f05d18708 + winnt-i386 df50210f41db9a6f2968be5773b8e3bae32bb823 + winnt-x86_64 d7774b724988485652781a804bdf8e05d28ead48 + S 2015-05-24 ba0e1cd bitrig-x86_64 2a710e16e3e3ef3760df1f724d66b3af34c1ef3f freebsd-x86_64 370db40613f5c08563ed7e38357826dd42d4e0f8 diff --git a/src/libstd/bool.rs b/src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs similarity index 71% rename from src/libstd/bool.rs rename to src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs index df703b3e43e32..6e8f80c8f5f9f 100644 --- a/src/libstd/bool.rs +++ b/src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The boolean type +#![feature(optin_builtin_traits)] -#![doc(primitive = "bool")] -#![stable(feature = "rust1", since = "1.0.0")] +pub trait AnOibit {} + +impl AnOibit for .. {} diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/compile-fail/cfg-empty-codemap.rs similarity index 70% rename from src/test/compile-fail/feature-gate-negate-unsigned.rs rename to src/test/compile-fail/cfg-empty-codemap.rs index 7dc654fe1c8d5..4c27d57008d04 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned.rs +++ b/src/test/compile-fail/cfg-empty-codemap.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that negating unsigned integers is gated by `negate_unsigned` feature -// gate +// Tests that empty codemaps don't ICE (#23301) -const MAX: usize = -1; -//~^ ERROR unary negation of unsigned integers may be removed in the future +// compile-flags: --cfg "" -fn main() {} +// error-pattern: expected ident, found + +pub fn main() { +} diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index 19b5f9b094c13..f991e5328c104 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -17,7 +17,6 @@ // evaluation below (e.g. that performed by trans and llvm), so if you // change this warn to a deny, then the compiler will exit before // those errors are detected. -#![warn(unsigned_negation)] use std::fmt; use std::{i8, i16, i32, i64, isize}; @@ -69,8 +68,6 @@ const VALS_I64: (i64, i64, i64, i64) = const VALS_U8: (u8, u8, u8, u8) = (-u8::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u8::MIN - 1, //~^ ERROR attempted to sub with overflow u8::MAX + 1, @@ -81,8 +78,6 @@ const VALS_U8: (u8, u8, u8, u8) = const VALS_U16: (u16, u16, u16, u16) = (-u16::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u16::MIN - 1, //~^ ERROR attempted to sub with overflow u16::MAX + 1, @@ -93,8 +88,6 @@ const VALS_U16: (u16, u16, u16, u16) = const VALS_U32: (u32, u32, u32, u32) = (-u32::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u32::MIN - 1, //~^ ERROR attempted to sub with overflow u32::MAX + 1, @@ -105,8 +98,6 @@ const VALS_U32: (u32, u32, u32, u32) = const VALS_U64: (u64, u64, u64, u64) = (-u64::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u64::MIN - 1, //~^ ERROR attempted to sub with overflow u64::MAX + 1, diff --git a/src/test/compile-fail/issue-20162.rs b/src/test/compile-fail/issue-20162.rs new file mode 100644 index 0000000000000..d3a87689ac5e1 --- /dev/null +++ b/src/test/compile-fail/issue-20162.rs @@ -0,0 +1,17 @@ +// 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. + +struct X { x: i32 } + +fn main() { + let mut b: Vec = vec![]; + b.sort(); + //~^ ERROR the trait `core::cmp::Ord` is not implemented for the type `X` +} diff --git a/src/test/compile-fail/issue-21174.rs b/src/test/compile-fail/issue-21174.rs index ec258449cb161..30fd2eb4d2f9a 100644 --- a/src/test/compile-fail/issue-21174.rs +++ b/src/test/compile-fail/issue-21174.rs @@ -15,7 +15,7 @@ trait Trait<'a> { fn foo<'a, T: Trait<'a>>(value: T::A) { let new: T::B = unsafe { std::mem::transmute(value) }; -//~^ ERROR: cannot transmute to or from a type that contains type parameters in its interior [E0139] +//~^ ERROR: cannot transmute to or from a type that contains unsubstituted type parameters [E0139] } fn main() { } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index 5867bc2f09deb..160551b81cb2e 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(negate_unsigned)] #![deny(exceeding_bitshifts)] #![allow(unused_variables)] #![allow(dead_code)] -#![feature(num_bits_bytes, negate_unsigned)] +#![feature(num_bits_bytes)] fn main() { let n = 1u8 << 7; @@ -60,4 +59,7 @@ fn main() { let n = 1_isize << std::isize::BITS; //~ ERROR: bitshift exceeds the type's number of bits let n = 1_usize << std::usize::BITS; //~ ERROR: bitshift exceeds the type's number of bits + + + let n = 1i8<<(1isize+-1); } diff --git a/src/test/compile-fail/lint-missing-doc.rs b/src/test/compile-fail/lint-missing-doc.rs index 5501835886104..04db6c8c8f39c 100644 --- a/src/test/compile-fail/lint-missing-doc.rs +++ b/src/test/compile-fail/lint-missing-doc.rs @@ -149,27 +149,6 @@ pub enum PubBaz3 { #[doc(hidden)] pub fn baz() {} - -const FOO: u32 = 0; -/// dox -pub const FOO1: u32 = 0; -#[allow(missing_docs)] -pub const FOO2: u32 = 0; -#[doc(hidden)] -pub const FOO3: u32 = 0; -pub const FOO4: u32 = 0; //~ ERROR: missing documentation for a const - - -static BAR: u32 = 0; -/// dox -pub static BAR1: u32 = 0; -#[allow(missing_docs)] -pub static BAR2: u32 = 0; -#[doc(hidden)] -pub static BAR3: u32 = 0; -pub static BAR4: u32 = 0; //~ ERROR: missing documentation for a static - - mod internal_impl { /// dox pub fn documented() {} diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs index 42515e0f00c76..839d50ae63f90 100644 --- a/src/test/compile-fail/lint-type-limits.rs +++ b/src/test/compile-fail/lint-type-limits.rs @@ -50,14 +50,3 @@ fn qux() { i += 1; } } - -fn quy() { - let i = -23_usize; //~ WARNING negation of unsigned int literal may be unintentional - //~^ WARNING unused variable -} - -fn quz() { - let i = 23_usize; - let j = -i; //~ WARNING negation of unsigned int variable may be unintentional - //~^ WARNING unused variable -} diff --git a/src/test/compile-fail/match-range-fail-2.rs b/src/test/compile-fail/match-range-fail-2.rs new file mode 100644 index 0000000000000..e30f783ce3637 --- /dev/null +++ b/src/test/compile-fail/match-range-fail-2.rs @@ -0,0 +1,23 @@ +// 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. + +fn main() { + match 5 { + 6 ... 1 => { } + _ => { } + }; + //~^^^ ERROR lower range bound must be less than or equal to upper + + match 5u64 { + 0xFFFF_FFFF_FFFF_FFFF ... 1 => { } + _ => { } + }; + //~^^^ ERROR lower range bound must be less than or equal to upper +} diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 234b74f76d1e0..05b870b8f41cc 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -9,12 +9,6 @@ // except according to those terms. fn main() { - match 5 { - 6 ... 1 => { } - _ => { } - }; - //~^^^ ERROR lower range bound must be less than or equal to upper - match "wow" { "bar" ... "foo" => { } }; diff --git a/src/test/compile-fail/regions-static-bound.rs b/src/test/compile-fail/regions-static-bound.rs new file mode 100644 index 0000000000000..297b6a866da3a --- /dev/null +++ b/src/test/compile-fail/regions-static-bound.rs @@ -0,0 +1,24 @@ +// 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. + +fn static_id<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'static { t } +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + t //~ ERROR cannot infer an appropriate lifetime +} + +fn error(u: &(), v: &()) { + static_id(&u); //~ ERROR cannot infer an appropriate lifetime + static_id_indirect(&v); //~ ERROR cannot infer an appropriate lifetime +} + +fn main() {} diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index 121581412202c..7a0623ba44f02 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -12,47 +12,58 @@ fn main() { let n = 1; - let a = [0; n]; //~ ERROR expected constant integer for repeat count, found variable + let a = [0; n]; + //~^ ERROR expected constant integer for repeat count, found variable [E0307] let b = [0; ()]; -//~^ ERROR mismatched types -//~| expected `usize` -//~| found `()` -//~| expected usize -//~| found () -//~| ERROR expected positive integer for repeat count, found tuple + //~^ ERROR mismatched types + //~| expected `usize` + //~| found `()` + //~| expected usize + //~| found ()) [E0308] + //~| ERROR expected positive integer for repeat count, found tuple [E0306] let c = [0; true]; //~^ ERROR mismatched types //~| expected `usize` //~| found `bool` //~| expected usize - //~| found bool - //~| ERROR expected positive integer for repeat count, found boolean + //~| found bool) [E0308] + //~| ERROR expected positive integer for repeat count, found boolean [E0306] let d = [0; 0.5]; //~^ ERROR mismatched types //~| expected `usize` //~| found `_` //~| expected usize - //~| found floating-point variable - //~| ERROR expected positive integer for repeat count, found float + //~| found floating-point variable) [E0308] + //~| ERROR expected positive integer for repeat count, found float [E0306] let e = [0; "foo"]; //~^ ERROR mismatched types //~| expected `usize` //~| found `&'static str` //~| expected usize - //~| found &-ptr - //~| ERROR expected positive integer for repeat count, found string + //~| found &-ptr) [E0308] + //~| ERROR expected positive integer for repeat count, found string literal [E0306] let f = [0; -4_isize]; //~^ ERROR mismatched types //~| expected `usize` //~| found `isize` //~| expected usize - //~| found isize - //~| ERROR expected positive integer for repeat count, found negative integer + //~| found isize) [E0308] + //~| ERROR expected positive integer for repeat count, found negative integer [E0306] let f = [0_usize; -1_isize]; //~^ ERROR mismatched types //~| expected `usize` //~| found `isize` //~| expected usize - //~| found isize - //~| ERROR expected positive integer for repeat count, found negative integer + //~| found isize) [E0308] + //~| ERROR expected positive integer for repeat count, found negative integer [E0306] + struct G { + g: (), + } + let g = [0; G { g: () }]; + //~^ ERROR mismatched types + //~| expected `usize` + //~| found `main::G` + //~| expected usize + //~| found struct `main::G`) [E0308] + //~| ERROR expected positive integer for repeat count, found struct [E0306] } diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 0134a058c992b..2468150a6a5b1 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -42,8 +42,10 @@ // gdb-check:type = f32 // gdb-command:whatis f64 // gdb-check:type = f64 +// gdb-command:whatis fnptr +// gdb-check:type = [...] (*)([...]) // gdb-command:info functions _yyy -// gdb-check:[...]![...]_yyy([...])([...]); +// gdb-check:[...]![...]_yyy([...]); // gdb-command:continue #![allow(unused_variables)] @@ -65,6 +67,7 @@ fn main() { let u64: u64 = 64; let f32: f32 = 2.5; let f64: f64 = 3.5; + let fnptr : fn() = _zzz; _zzz(); // #break if 1 == 1 { _yyy(); } } diff --git a/src/test/parse-fail/macro-doc-comments-1.rs b/src/test/parse-fail/macro-doc-comments-1.rs new file mode 100644 index 0000000000000..03bcef4fa5ee0 --- /dev/null +++ b/src/test/parse-fail/macro-doc-comments-1.rs @@ -0,0 +1,19 @@ +// 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. + +macro_rules! outer { + (#[$outer:meta]) => () +} + +outer! { + //! Inner +} //~^ ERROR no rules expected the token `!` + +fn main() { } diff --git a/src/test/parse-fail/macro-doc-comments-2.rs b/src/test/parse-fail/macro-doc-comments-2.rs new file mode 100644 index 0000000000000..a1b112c29b6e0 --- /dev/null +++ b/src/test/parse-fail/macro-doc-comments-2.rs @@ -0,0 +1,19 @@ +// 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. + +macro_rules! inner { + (#![$inner:meta]) => () +} + +inner! { + /// Outer +} //~^ ERROR no rules expected the token `[` + +fn main() { } diff --git a/src/test/run-pass/dropck_legal_cycles.rs b/src/test/run-pass/dropck_legal_cycles.rs new file mode 100644 index 0000000000000..b4f9b3f945809 --- /dev/null +++ b/src/test/run-pass/dropck_legal_cycles.rs @@ -0,0 +1,759 @@ +// 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. + +// This test exercises cases where cyclic structure is legal, +// including when the cycles go through data-structures such +// as `Vec` or `TypedArena`. +// +// The intent is to cover as many such cases as possible, ensuring +// that if the compiler did not complain circa Rust 1.x (1.2 as of +// this writing), then it will continue to not complain in the future. +// +// Note that while some of the tests are only exercising using the +// given collection as a "backing store" for a set of nodes that hold +// the actual cycle (and thus the cycle does not go through the +// collection itself in such cases), in general we *do* want to make +// sure to have at least one example exercising a cycle that goes +// through the collection, for every collection type that supports +// this. + +#![feature(vecmap)] + +use std::cell::Cell; +use std::cmp::Ordering; +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::LinkedList; +use std::collections::VecDeque; +use std::collections::VecMap; +use std::collections::btree_map::BTreeMap; +use std::collections::btree_set::BTreeSet; +use std::hash::{Hash, Hasher}; + +const PRINT: bool = false; + +pub fn main() { + let c_orig = ContextData { + curr_depth: 0, + max_depth: 3, + visited: 0, + max_visits: 1000, + skipped: 0, + curr_mark: 0, + saw_prev_marked: false, + }; + + // Cycle 1: { v[0] -> v[1], v[1] -> v[0] }; + // does not exercise `v` itself + let v: Vec = vec![Named::new("s0"), + Named::new("s1")]; + v[0].next.set(Some(&v[1])); + v[1].next.set(Some(&v[0])); + + let mut c = c_orig.clone(); + c.curr_mark = 10; + assert!(!c.saw_prev_marked); + v[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 2: { v[0] -> v, v[1] -> v } + let v: V = Named::new("v"); + v.contents[0].set(Some(&v)); + v.contents[1].set(Some(&v)); + + let mut c = c_orig.clone(); + c.curr_mark = 20; + assert!(!c.saw_prev_marked); + v.for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 3: { hk0 -> hv0, hv0 -> hk0, hk1 -> hv1, hv1 -> hk1 }; + // does not exercise `h` itself + + let mut h: HashMap = HashMap::new(); + h.insert(Named::new("hk0"), Named::new("hv0")); + h.insert(Named::new("hk1"), Named::new("hv1")); + for (key, val) in h.iter() { + val.next.set(Some(key)); + key.next.set(Some(val)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 30; + for (key, _) in h.iter() { + c.curr_mark += 1; + c.saw_prev_marked = false; + key.for_each_child(&mut c); + assert!(c.saw_prev_marked); + } + + if PRINT { println!(""); } + + // Cycle 4: { h -> (hmk0,hmv0,hmk1,hmv1), {hmk0,hmv0,hmk1,hmv1} -> h } + + let mut h: HashMap = HashMap::new(); + h.insert(Named::new("hmk0"), Named::new("hmv0")); + h.insert(Named::new("hmk0"), Named::new("hmv0")); + for (key, val) in h.iter() { + val.contents.set(Some(&h)); + key.contents.set(Some(&h)); + } + + let mut c = c_orig.clone(); + c.max_depth = 2; + c.curr_mark = 40; + for (key, _) in h.iter() { + c.curr_mark += 1; + c.saw_prev_marked = false; + key.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 5: { vd[0] -> vd[1], vd[1] -> vd[0] }; + // does not exercise vd itself + let mut vd: VecDeque = VecDeque::new(); + vd.push_back(Named::new("d0")); + vd.push_back(Named::new("d1")); + vd[0].next.set(Some(&vd[1])); + vd[1].next.set(Some(&vd[0])); + + let mut c = c_orig.clone(); + c.curr_mark = 50; + assert!(!c.saw_prev_marked); + vd[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 6: { vd -> (vd0, vd1), {vd0, vd1} -> vd } + let mut vd: VecDeque = VecDeque::new(); + vd.push_back(Named::new("vd0")); + vd.push_back(Named::new("vd1")); + vd[0].contents.set(Some(&vd)); + vd[1].contents.set(Some(&vd)); + + let mut c = c_orig.clone(); + c.curr_mark = 60; + assert!(!c.saw_prev_marked); + vd[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 7: { vm -> (vm0, vm1), {vm0, vm1} -> vm } + let mut vm: VecMap = VecMap::new(); + vm.insert(0, Named::new("vm0")); + vm.insert(1, Named::new("vm1")); + vm[0].contents.set(Some(&vm)); + vm[1].contents.set(Some(&vm)); + + let mut c = c_orig.clone(); + c.curr_mark = 70; + assert!(!c.saw_prev_marked); + vm[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 8: { ll -> (ll0, ll1), {ll0, ll1} -> ll } + let mut ll: LinkedList = LinkedList::new(); + ll.push_back(Named::new("ll0")); + ll.push_back(Named::new("ll1")); + for e in &ll { + e.contents.set(Some(&ll)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 80; + for e in &ll { + c.curr_mark += 1; + c.saw_prev_marked = false; + e.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 9: { bh -> (bh0, bh1), {bh0, bh1} -> bh } + let mut bh: BinaryHeap = BinaryHeap::new(); + bh.push(Named::new("bh0")); + bh.push(Named::new("bh1")); + for b in bh.iter() { + b.contents.set(Some(&bh)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 90; + for b in &bh { + c.curr_mark += 1; + c.saw_prev_marked = false; + b.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 10: { btm -> (btk0, btv1), {bt0, bt1} -> btm } + let mut btm: BTreeMap = BTreeMap::new(); + btm.insert(Named::new("btk0"), Named::new("btv0")); + btm.insert(Named::new("btk1"), Named::new("btv1")); + for (k, v) in btm.iter() { + k.contents.set(Some(&btm)); + v.contents.set(Some(&btm)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 100; + for (k, _) in &btm { + c.curr_mark += 1; + c.saw_prev_marked = false; + k.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 10: { bts -> (bts0, bts1), {bts0, bts1} -> btm } + let mut bts: BTreeSet = BTreeSet::new(); + bts.insert(Named::new("bts0")); + bts.insert(Named::new("bts1")); + for v in bts.iter() { + v.contents.set(Some(&bts)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 100; + for b in &bts { + c.curr_mark += 1; + c.saw_prev_marked = false; + b.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } +} + +trait Named { + fn new(&'static str) -> Self; + fn name(&self) -> &str; +} + +trait Marked { + fn mark(&self) -> M; + fn set_mark(&self, mark: M); +} + +struct S<'a> { + name: &'static str, + mark: Cell, + next: Cell>>, +} + +impl<'a> Named for S<'a> { + fn new<'b>(name: &'static str) -> S<'b> { + S { name: name, mark: Cell::new(0), next: Cell::new(None) } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for S<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct V<'a> { + name: &'static str, + mark: Cell, + contents: Vec>>>, +} + +impl<'a> Named for V<'a> { + fn new<'b>(name: &'static str) -> V<'b> { + V { name: name, + mark: Cell::new(0), + contents: vec![Cell::new(None), Cell::new(None)] + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for V<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +#[derive(Eq)] +struct H<'a> { + name: &'static str, + mark: Cell, + next: Cell>>, +} + +impl<'a> Named for H<'a> { + fn new<'b>(name: &'static str) -> H<'b> { + H { name: name, mark: Cell::new(0), next: Cell::new(None) } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for H<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> PartialEq for H<'a> { + fn eq(&self, rhs: &H<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> Hash for H<'a> { + fn hash(&self, state: &mut H) { + self.name.hash(state) + } +} + +#[derive(Eq)] +struct HM<'a> { + name: &'static str, + mark: Cell, + contents: Cell, HM<'a>>>>, +} + +impl<'a> Named for HM<'a> { + fn new<'b>(name: &'static str) -> HM<'b> { + HM { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for HM<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> PartialEq for HM<'a> { + fn eq(&self, rhs: &HM<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> Hash for HM<'a> { + fn hash(&self, state: &mut H) { + self.name.hash(state) + } +} + + +struct VD<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for VD<'a> { + fn new<'b>(name: &'static str) -> VD<'b> { + VD { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for VD<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct VM<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for VM<'a> { + fn new<'b>(name: &'static str) -> VM<'b> { + VM { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for VM<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct LL<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for LL<'a> { + fn new<'b>(name: &'static str) -> LL<'b> { + LL { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for LL<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct BH<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for BH<'a> { + fn new<'b>(name: &'static str) -> BH<'b> { + BH { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for BH<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> Eq for BH<'a> { } + +impl<'a> PartialEq for BH<'a> { + fn eq(&self, rhs: &BH<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> PartialOrd for BH<'a> { + fn partial_cmp(&self, rhs: &BH<'a>) -> Option { + Some(self.cmp(rhs)) + } +} + +impl<'a> Ord for BH<'a> { + fn cmp(&self, rhs: &BH<'a>) -> Ordering { + self.name.cmp(rhs.name) + } +} + +struct BTM<'a> { + name: &'static str, + mark: Cell, + contents: Cell, BTM<'a>>>>, +} + +impl<'a> Named for BTM<'a> { + fn new<'b>(name: &'static str) -> BTM<'b> { + BTM { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for BTM<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> Eq for BTM<'a> { } + +impl<'a> PartialEq for BTM<'a> { + fn eq(&self, rhs: &BTM<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> PartialOrd for BTM<'a> { + fn partial_cmp(&self, rhs: &BTM<'a>) -> Option { + Some(self.cmp(rhs)) + } +} + +impl<'a> Ord for BTM<'a> { + fn cmp(&self, rhs: &BTM<'a>) -> Ordering { + self.name.cmp(rhs.name) + } +} + +struct BTS<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for BTS<'a> { + fn new<'b>(name: &'static str) -> BTS<'b> { + BTS { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for BTS<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> Eq for BTS<'a> { } + +impl<'a> PartialEq for BTS<'a> { + fn eq(&self, rhs: &BTS<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> PartialOrd for BTS<'a> { + fn partial_cmp(&self, rhs: &BTS<'a>) -> Option { + Some(self.cmp(rhs)) + } +} + +impl<'a> Ord for BTS<'a> { + fn cmp(&self, rhs: &BTS<'a>) -> Ordering { + self.name.cmp(rhs.name) + } +} + + +trait Context { + fn should_act(&self) -> bool; + fn increase_visited(&mut self); + fn increase_skipped(&mut self); + fn increase_depth(&mut self); + fn decrease_depth(&mut self); +} + +trait PrePost { + fn pre(&mut self, &T); + fn post(&mut self, &T); + fn hit_limit(&mut self, &T); +} + +trait Children<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost, Self: Sized; + + fn descend_into_self(&self, context: &mut C) + where C: Context + PrePost, Self: Sized + { + context.pre(self); + if context.should_act() { + context.increase_visited(); + context.increase_depth(); + self.for_each_child(context); + context.decrease_depth(); + } else { + context.hit_limit(self); + context.increase_skipped(); + } + context.post(self); + } + + fn descend<'b, C>(&self, c: &Cell>, context: &mut C) + where C: Context + PrePost, Self: Sized + { + if let Some(r) = c.get() { + r.descend_into_self(context); + } + } +} + +impl<'a> Children<'a> for S<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + self.descend(&self.next, context); + } +} + +impl<'a> Children<'a> for V<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + for r in &self.contents { + self.descend(r, context); + } + } +} + +impl<'a> Children<'a> for H<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + self.descend(&self.next, context); + } +} + +impl<'a> Children<'a> for HM<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref hm) = self.contents.get() { + for (k, v) in hm.iter() { + for r in &[k, v] { + r.descend_into_self(context); + } + } + } + } +} + +impl<'a> Children<'a> for VD<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref vd) = self.contents.get() { + for r in vd.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for VM<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref vd) = self.contents.get() { + for (_idx, r) in vd.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for LL<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref ll) = self.contents.get() { + for r in ll.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for BH<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref bh) = self.contents.get() { + for r in bh.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for BTM<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref bh) = self.contents.get() { + for (k, v) in bh.iter() { + for r in &[k, v] { + r.descend_into_self(context); + } + } + } + } +} + +impl<'a> Children<'a> for BTS<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref bh) = self.contents.get() { + for r in bh.iter() { + r.descend_into_self(context); + } + } + } +} + +#[derive(Copy, Clone)] +struct ContextData { + curr_depth: usize, + max_depth: usize, + visited: usize, + max_visits: usize, + skipped: usize, + curr_mark: u32, + saw_prev_marked: bool, +} + +impl Context for ContextData { + fn should_act(&self) -> bool { + self.curr_depth < self.max_depth && self.visited < self.max_visits + } + fn increase_visited(&mut self) { self.visited += 1; } + fn increase_skipped(&mut self) { self.skipped += 1; } + fn increase_depth(&mut self) { self.curr_depth += 1; } + fn decrease_depth(&mut self) { self.curr_depth -= 1; } +} + +impl> PrePost for ContextData { + fn pre(&mut self, t: &T) { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("prev {}", t.name()); } + if t.mark() == self.curr_mark { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("(probably previously marked)"); } + self.saw_prev_marked = true; + } + t.set_mark(self.curr_mark); + } + fn post(&mut self, t: &T) { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("post {}", t.name()); } + } + fn hit_limit(&mut self, t: &T) { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("LIMIT {}", t.name()); } + } +} diff --git a/src/test/run-pass/feature-gate-negate-unsigned.rs b/src/test/run-pass/feature-gate-negate-unsigned.rs new file mode 100644 index 0000000000000..95c8e62be53bc --- /dev/null +++ b/src/test/run-pass/feature-gate-negate-unsigned.rs @@ -0,0 +1,38 @@ +// 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. + +// Test that negating unsigned integers is gated by `negate_unsigned` feature +// gate + +struct S; +impl std::ops::Neg for S { + type Output = u32; + fn neg(self) -> u32 { 0 } +} + +const _MAX: usize = -1; +//~^ WARN unary negation of unsigned integers will be feature gated in the future + +fn main() { + let a = -1; + //~^ WARN unary negation of unsigned integers will be feature gated in the future + let _b : u8 = a; // for infering variable a to u8. + + -a; + //~^ WARN unary negation of unsigned integers will be feature gated in the future + + let _d = -1u8; + //~^ WARN unary negation of unsigned integers will be feature gated in the future + + for _ in -10..10u8 {} + //~^ WARN unary negation of unsigned integers will be feature gated in the future + + -S; // should not trigger the gate; issue 26840 +} diff --git a/src/test/run-pass/issue-10436.rs b/src/test/run-pass/issue-10436.rs new file mode 100644 index 0000000000000..81a955b0f22e4 --- /dev/null +++ b/src/test/run-pass/issue-10436.rs @@ -0,0 +1,20 @@ +// 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. + +fn works(x: T) -> Vec { vec![x] } + +fn also_works(x: T) -> Vec { vec![x] } + +fn main() { + let _: Vec = works(0); + let _: Vec = also_works(0); + let _ = works(0); + let _ = also_works(0); +} diff --git a/src/test/run-pass/issue-14229.rs b/src/test/run-pass/issue-14229.rs new file mode 100644 index 0000000000000..ee2bbe63750c3 --- /dev/null +++ b/src/test/run-pass/issue-14229.rs @@ -0,0 +1,30 @@ +// 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. + +trait Foo: Sized { + fn foo(self) {} +} + +trait Bar: Sized { + fn bar(self) {} +} + +struct S; + +impl<'l> Foo for &'l S {} + +impl Bar for T {} + +fn main() { + let s = S; + s.foo(); + (&s).bar(); + s.bar(); +} diff --git a/src/test/run-pass/issue-14382.rs b/src/test/run-pass/issue-14382.rs new file mode 100644 index 0000000000000..cdb44f6a60675 --- /dev/null +++ b/src/test/run-pass/issue-14382.rs @@ -0,0 +1,24 @@ +// 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. + +#[derive(Debug)] +struct Matrix4(S); +trait POrd {} + +fn translate>(s: S) -> Matrix4 { Matrix4(s) } + +impl POrd for f32 {} +impl POrd for f64 {} + +fn main() { + let x = 1.0; + let m : Matrix4 = translate(x); + println!("m: {:?}", m); +} diff --git a/src/test/run-pass/issue-19404.rs b/src/test/run-pass/issue-19404.rs new file mode 100644 index 0000000000000..0eea6ba22cae8 --- /dev/null +++ b/src/test/run-pass/issue-19404.rs @@ -0,0 +1,47 @@ +// 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. + +#![feature(reflect_marker)] + +use std::any::TypeId; +use std::marker::Reflect; +use std::rc::Rc; + +type Fp = Rc; + +struct Engine; + +trait Component: 'static + Reflect {} +impl Component for Engine {} + +trait Env { + fn get_component_type_id(&self, type_id: TypeId) -> Option>; +} + +impl<'a> Env+'a { + fn get_component(&self) -> Option> { + let x = self.get_component_type_id(TypeId::of::()); + None + } +} + +trait Figment { + fn init(&mut self, env: &Env); +} + +struct MyFigment; + +impl Figment for MyFigment { + fn init(&mut self, env: &Env) { + let engine = env.get_component::(); + } +} + +fn main() {} diff --git a/src/test/run-pass/issue-25343.rs b/src/test/run-pass/issue-25343.rs new file mode 100644 index 0000000000000..9e01d577276b8 --- /dev/null +++ b/src/test/run-pass/issue-25343.rs @@ -0,0 +1,16 @@ +// 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. + +fn main() { + || { + 'label: loop { + } + }; +} diff --git a/src/test/run-pass/issue-26468.rs b/src/test/run-pass/issue-26468.rs new file mode 100644 index 0000000000000..9fb8675e84e9d --- /dev/null +++ b/src/test/run-pass/issue-26468.rs @@ -0,0 +1,38 @@ +// 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. + +#![allow(dead_code)] + +enum FooMode { + Check = 0x1001, +} + +enum BarMode { + Check = 0x2001, +} + +enum Mode { + Foo(FooMode), + Bar(BarMode), +} + +#[inline(never)] +fn broken(mode: &Mode) -> u32 { + for _ in 0..1 { + if let Mode::Foo(FooMode::Check) = *mode { return 17 } + if let Mode::Bar(BarMode::Check) = *mode { return 19 } + } + return 42; +} + +fn main() { + let mode = Mode::Bar(BarMode::Check); + assert_eq!(broken(&mode), 19); +} diff --git a/src/test/run-pass/issue-26484.rs b/src/test/run-pass/issue-26484.rs new file mode 100644 index 0000000000000..d3e6fc85f136f --- /dev/null +++ b/src/test/run-pass/issue-26484.rs @@ -0,0 +1,20 @@ +// 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. + +// compile-flags:-g + +fn helper bool>(_f: F) { + print!(""); +} + +fn main() { + let cond = 0; + helper(|v| v == cond) +} diff --git a/src/test/run-pass/issue-26802.rs b/src/test/run-pass/issue-26802.rs new file mode 100644 index 0000000000000..854340b0eae29 --- /dev/null +++ b/src/test/run-pass/issue-26802.rs @@ -0,0 +1,23 @@ +// 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. + +trait Foo<'a> { + fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 } +} + +pub struct FooBar; +impl Foo<'static> for FooBar {} +fn test(foobar: FooBar) -> Box> { + Box::new(foobar) +} + +fn main() { + assert_eq!(test(FooBar).bar(&4), 11); +} diff --git a/src/test/run-pass/macro-doc-comments.rs b/src/test/run-pass/macro-doc-comments.rs new file mode 100644 index 0000000000000..506813df5b374 --- /dev/null +++ b/src/test/run-pass/macro-doc-comments.rs @@ -0,0 +1,33 @@ +// 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. + +macro_rules! doc { + ( + $(#[$outer:meta])* + mod $i:ident { + $(#![$inner:meta])* + } + ) => + ( + $(#[$outer])* + pub mod $i { + $(#![$inner])* + } + ) +} + +doc! { + /// Outer doc + mod Foo { + //! Inner doc + } +} + +fn main() { } diff --git a/src/test/run-pass/regions-static-bound.rs b/src/test/run-pass/regions-static-bound.rs new file mode 100644 index 0000000000000..1c6411e3b8f11 --- /dev/null +++ b/src/test/run-pass/regions-static-bound.rs @@ -0,0 +1,28 @@ +// 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. + +fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () + where 'a: 'static { t } +fn static_id<'a>(t: &'a ()) -> &'static () + where 'a: 'static { t } +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t } + +static UNIT: () = (); + +fn main() +{ + let mut val : &'static () = &UNIT; + invariant_id(&mut val); + static_id(val); + static_id_indirect(val); + ref_id(val); +} diff --git a/src/test/rustdoc/impl-parts-crosscrate.rs b/src/test/rustdoc/impl-parts-crosscrate.rs new file mode 100644 index 0000000000000..5fa2e03e0a884 --- /dev/null +++ b/src/test/rustdoc/impl-parts-crosscrate.rs @@ -0,0 +1,30 @@ +// 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. + +// aux-build:rustdoc-impl-parts-crosscrate.rs +// ignore-cross-compile + +#![feature(optin_builtin_traits)] + +extern crate rustdoc_impl_parts_crosscrate; + +pub struct Bar { t: T } + +// The output file is html embeded in javascript, so the html tags +// aren't stripped by the processing script and we can't check for the +// full impl string. Instead, just make sure something from each part +// is mentioned. + +// @has implementors/rustdoc_impl_parts_crosscrate/trait.AnOibit.js Bar +// @has - Send +// @has - !AnOibit +// @has - Copy +impl !rustdoc_impl_parts_crosscrate::AnOibit for Bar + where T: Copy {} diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs new file mode 100644 index 0000000000000..89c5e60e34314 --- /dev/null +++ b/src/test/rustdoc/impl-parts.rs @@ -0,0 +1,23 @@ +// 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. + +#![feature(optin_builtin_traits)] + +pub trait AnOibit {} + +impl AnOibit for .. {} + +pub struct Foo { field: T } + +// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \ +// "impl !AnOibit for Foo where T: Sync" +// @has impl_parts/trait.AnOibit.html '//*[@class="item-list"]//code' \ +// "impl !AnOibit for Foo where T: Sync" +impl !AnOibit for Foo where T: Sync {} diff --git a/src/test/rustdoc/issue-23812.rs b/src/test/rustdoc/issue-23812.rs new file mode 100644 index 0000000000000..37f6749694c40 --- /dev/null +++ b/src/test/rustdoc/issue-23812.rs @@ -0,0 +1,46 @@ +// 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. + +macro_rules! doc { + (#[$outer:meta] mod $i:ident { #![$inner:meta] }) => + ( + #[$outer] + pub mod $i { + #![$inner] + } + ) +} + +doc! { + /// Outer comment + mod Foo { + //! Inner comment + } +} + +// @has issue_23812/Foo/index.html +// @has - 'Outer comment' +// @!has - '/// Outer comment' +// @has - 'Inner comment' +// @!has - '//! Inner comment' + + +doc! { + /** Outer block comment */ + mod Bar { + /*! Inner block comment */ + } +} + +// @has issue_23812/Bar/index.html +// @has - 'Outer block comment' +// @!has - '/** Outer block comment */' +// @has - 'Inner block comment' +// @!has - '/*! Inner block comment */'