diff --git a/configure b/configure index da5468a0ce61d..fdef550a6451a 100755 --- a/configure +++ b/configure @@ -717,18 +717,6 @@ if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; f if [ -n "$CFG_ENABLE_ORBIT" ]; then putvar CFG_ENABLE_ORBIT; fi -# A magic value that allows the compiler to use unstable features -# during the bootstrap even when doing so would normally be an error -# because of feature staging or because the build turns on -# warnings-as-errors and unstable features default to warnings. The -# build has to match this key in an env var. Meant to be a mild -# deterrent from users just turning on unstable features on the stable -# channel. -# Basing CFG_BOOTSTRAP_KEY on CFG_BOOTSTRAP_KEY lets it get picked up -# during a Makefile reconfig. -CFG_BOOTSTRAP_KEY="${CFG_BOOTSTRAP_KEY-`date +%H:%M:%S`}" -putvar CFG_BOOTSTRAP_KEY - step_msg "looking for build programs" probe_need CFG_CURLORWGET curl wget diff --git a/mk/main.mk b/mk/main.mk index a32658ddcefdc..9b8080f96610f 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -24,6 +24,17 @@ CFG_PRERELEASE_VERSION=.1 # versions in the same place CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND)) +# A magic value that allows the compiler to use unstable features during the +# bootstrap even when doing so would normally be an error because of feature +# staging or because the build turns on warnings-as-errors and unstable features +# default to warnings. The build has to match this key in an env var. +# +# This value is keyed off the release to ensure that all compilers for one +# particular release have the same bootstrap key. Note that this is +# intentionally not "secure" by any definition, this is largely just a deterrent +# from users enabling unstable features on the stable compiler. +CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA) + ifeq ($(CFG_RELEASE_CHANNEL),stable) # This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly" CFG_RELEASE=$(CFG_RELEASE_NUM) diff --git a/src/doc/book/concurrency.md b/src/doc/book/concurrency.md index 87d551b68df07..8f1a0b5024500 100644 --- a/src/doc/book/concurrency.md +++ b/src/doc/book/concurrency.md @@ -127,9 +127,7 @@ thread may outlive the scope of `x`, leading to a dangling pointer. To fix this, we use a `move` closure as mentioned in the error message. `move` closures are explained in depth [here](closures.html#move-closures); basically -they move variables from their environment into themselves. This means that `x` -is now owned by the closure, and cannot be used in `main()` after the call to -`spawn()`. +they move variables from their environment into themselves. ```rust use std::thread; @@ -164,7 +162,7 @@ The same [ownership system](ownership.html) that helps prevent using pointers incorrectly also helps rule out data races, one of the worst kinds of concurrency bugs. -As an example, here is a Rust program that would have a data race in many +As an example, here is a Rust program that could have a data race in many languages. It will not compile: ```ignore @@ -197,6 +195,11 @@ thread, and the thread takes ownership of the reference, we'd have three owners! `data` gets moved out of `main` in the first call to `spawn()`, so subsequent calls in the loop cannot use this variable. +Note that this specific example will not cause a data race since different array +indices are being accessed. But this can't be determined at compile time, and in +a similar situation where `i` is a constant or is random, you would have a data +race. + So, we need some type that lets us have more than one owning reference to a value. Usually, we'd use `Rc` for this, which is a reference counted type that provides shared ownership. It has some runtime bookkeeping that keeps track diff --git a/src/doc/book/crates-and-modules.md b/src/doc/book/crates-and-modules.md index 0c9ed0bf12281..b3ccefe0a6b43 100644 --- a/src/doc/book/crates-and-modules.md +++ b/src/doc/book/crates-and-modules.md @@ -118,7 +118,7 @@ build deps examples libphrases-a7448e02a0468eaa.rlib native `libphrases-hash.rlib` is the compiled crate. Before we see how to use this crate from another crate, let’s break it up into multiple files. -# Multiple file crates +# Multiple File Crates If each crate were just one file, these files would get very large. It’s often easier to split up crates into multiple files, and Rust supports this in two @@ -190,13 +190,19 @@ mod farewells; ``` Again, these declarations tell Rust to look for either -`src/english/greetings.rs` and `src/japanese/greetings.rs` or -`src/english/farewells/mod.rs` and `src/japanese/farewells/mod.rs`. Because -these sub-modules don’t have their own sub-modules, we’ve chosen to make them -`src/english/greetings.rs` and `src/japanese/farewells.rs`. Whew! - -The contents of `src/english/greetings.rs` and `src/japanese/farewells.rs` are -both empty at the moment. Let’s add some functions. +`src/english/greetings.rs`, `src/english/farewells.rs`, +`src/japanese/greetings.rs` and `src/japanese/farewells.rs` or +`src/english/greetings/mod.rs`, `src/english/farewells/mod.rs`, +`src/japanese/greetings/mod.rs` and +`src/japanese/farewells/mod.rs`. Because these sub-modules don’t have +their own sub-modules, we’ve chosen to make them +`src/english/greetings.rs`, `src/english/farewells.rs`, +`src/japanese/greetings.rs` and `src/japanese/farewells.rs`. Whew! + +The contents of `src/english/greetings.rs`, +`src/english/farewells.rs`, `src/japanese/greetings.rs` and +`src/japanese/farewells.rs` are all empty at the moment. Let’s add +some functions. Put this in `src/english/greetings.rs`: diff --git a/src/doc/book/lifetimes.md b/src/doc/book/lifetimes.md index e7a4045d9b249..695b1614fb70c 100644 --- a/src/doc/book/lifetimes.md +++ b/src/doc/book/lifetimes.md @@ -56,8 +56,8 @@ To fix this, we have to make sure that step four never happens after step three. The ownership system in Rust does this through a concept called lifetimes, which describe the scope that a reference is valid for. -When we have a function that takes a reference by argument, we can be implicit -or explicit about the lifetime of the reference: +When we have a function that takes an argument by reference, we can be +implicit or explicit about the lifetime of the reference: ```rust // implicit diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 055029dddcddd..4aba567fa1c20 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -124,9 +124,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _ptr: Shared>, + ptr: Shared>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -144,9 +142,7 @@ impl, U: ?Sized> CoerceUnsized> for Arc {} #[unsafe_no_drop_flag] #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _ptr: Shared>, + ptr: Shared>, } #[stable(feature = "arc_weak", since = "1.4.0")] @@ -198,7 +194,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data: data, }; - Arc { _ptr: unsafe { Shared::new(Box::into_raw(x)) } } + Arc { ptr: unsafe { Shared::new(Box::into_raw(x)) } } } /// Unwraps the contained value if the `Arc` has exactly one strong reference. @@ -230,11 +226,11 @@ impl Arc { atomic::fence(Acquire); unsafe { - let ptr = *this._ptr; + let ptr = *this.ptr; let elem = ptr::read(&(*ptr).data); // Make a weak pointer to clean up the implicit strong-weak reference - let _weak = Weak { _ptr: this._ptr }; + let _weak = Weak { ptr: this.ptr }; mem::forget(this); Ok(elem) @@ -263,6 +259,7 @@ impl Arc { loop { // check if the weak counter is currently "locked"; if so, spin. if cur == usize::MAX { + cur = this.inner().weak.load(Relaxed); continue; } @@ -274,7 +271,7 @@ impl Arc { // synchronize with the write coming from `is_unique`, so that the // events prior to that write happen before this read. match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) { - Ok(_) => return Weak { _ptr: this._ptr }, + Ok(_) => return Weak { ptr: this.ptr }, Err(old) => cur = old, } } @@ -303,13 +300,13 @@ impl Arc { // `ArcInner` structure itself is `Sync` because the inner data is // `Sync` as well, so we're ok loaning out an immutable pointer to these // contents. - unsafe { &**self._ptr } + unsafe { &**self.ptr } } // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { - let ptr = *self._ptr; + let ptr = *self.ptr; // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). @@ -367,7 +364,7 @@ impl Clone for Arc { } } - Arc { _ptr: self._ptr } + Arc { ptr: self.ptr } } } @@ -435,7 +432,7 @@ impl Arc { // Materialize our own implicit weak pointer, so that it can clean // up the ArcInner as needed. - let weak = Weak { _ptr: this._ptr }; + let weak = Weak { ptr: this.ptr }; // mark the data itself as already deallocated unsafe { @@ -443,7 +440,7 @@ impl Arc { // here (due to zeroing) because data is no longer accessed by // other threads (due to there being no more strong refs at this // point). - let mut swap = Arc::new(ptr::read(&(**weak._ptr).data)); + let mut swap = Arc::new(ptr::read(&(**weak.ptr).data)); mem::swap(this, &mut swap); mem::forget(swap); } @@ -456,7 +453,7 @@ impl Arc { // As with `get_mut()`, the unsafety is ok because our reference was // either unique to begin with, or became one upon cloning the contents. unsafe { - let inner = &mut **this._ptr; + let inner = &mut **this.ptr; &mut inner.data } } @@ -488,7 +485,7 @@ impl Arc { // the Arc itself to be `mut`, so we're returning the only possible // reference to the inner data. unsafe { - let inner = &mut **this._ptr; + let inner = &mut **this.ptr; Some(&mut inner.data) } } else { @@ -557,7 +554,7 @@ impl Drop for Arc { // This structure has #[unsafe_no_drop_flag], so this drop glue may run // more than once (but it is guaranteed to be zeroed after the first if // it's run more than once) - let thin = *self._ptr as *const (); + let thin = *self.ptr as *const (); if thin as usize == mem::POST_DROP_USIZE { return; @@ -638,7 +635,7 @@ impl Weak { // Relaxed is valid for the same reason it is on Arc's Clone impl match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) { - Ok(_) => return Some(Arc { _ptr: self._ptr }), + Ok(_) => return Some(Arc { ptr: self.ptr }), Err(old) => n = old, } } @@ -647,7 +644,7 @@ impl Weak { #[inline] fn inner(&self) -> &ArcInner { // See comments above for why this is "safe" - unsafe { &**self._ptr } + unsafe { &**self.ptr } } } @@ -681,7 +678,7 @@ impl Clone for Weak { } } - return Weak { _ptr: self._ptr }; + return Weak { ptr: self.ptr }; } } @@ -713,7 +710,7 @@ impl Drop for Weak { /// } // implicit drop /// ``` fn drop(&mut self) { - let ptr = *self._ptr; + let ptr = *self.ptr; let thin = ptr as *const (); // see comments above for why this check is here @@ -885,7 +882,7 @@ impl fmt::Debug for Arc { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Arc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&*self._ptr, f) + fmt::Pointer::fmt(&*self.ptr, f) } } @@ -930,7 +927,7 @@ impl Weak { issue = "30425")] pub fn new() -> Weak { unsafe { - Weak { _ptr: Shared::new(Box::into_raw(box ArcInner { + Weak { ptr: Shared::new(Box::into_raw(box ArcInner { strong: atomic::AtomicUsize::new(0), weak: atomic::AtomicUsize::new(1), data: uninitialized(), diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index da803f57a59d3..c2f0a96132733 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -184,9 +184,7 @@ struct RcBox { #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { - // FIXME #12808: strange names to try to avoid interfering with field - // accesses of the contained type via Deref - _ptr: Shared>, + ptr: Shared>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -215,7 +213,7 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - _ptr: Shared::new(Box::into_raw(box RcBox { + ptr: Shared::new(Box::into_raw(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value: value, @@ -254,7 +252,7 @@ impl Rc { // pointer while also handling drop logic by just crafting a // fake Weak. this.dec_strong(); - let _weak = Weak { _ptr: this._ptr }; + let _weak = Weak { ptr: this.ptr }; forget(this); Ok(val) } @@ -287,7 +285,7 @@ impl Rc { #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { this.inc_weak(); - Weak { _ptr: this._ptr } + Weak { ptr: this.ptr } } /// Get the number of weak references to this value. @@ -348,7 +346,7 @@ impl Rc { #[stable(feature = "rc_unique", since = "1.4.0")] pub fn get_mut(this: &mut Self) -> Option<&mut T> { if Rc::is_unique(this) { - let inner = unsafe { &mut **this._ptr }; + let inner = unsafe { &mut **this.ptr }; Some(&mut inner.value) } else { None @@ -390,7 +388,7 @@ impl Rc { } else if Rc::weak_count(this) != 0 { // Can just steal the data, all that's left is Weaks unsafe { - let mut swap = Rc::new(ptr::read(&(**this._ptr).value)); + let mut swap = Rc::new(ptr::read(&(**this.ptr).value)); mem::swap(this, &mut swap); swap.dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake @@ -404,7 +402,7 @@ impl Rc { // reference count is guaranteed to be 1 at this point, and we required // the `Rc` itself to be `mut`, so we're returning the only possible // reference to the inner value. - let inner = unsafe { &mut **this._ptr }; + let inner = unsafe { &mut **this.ptr }; &mut inner.value } } @@ -449,7 +447,7 @@ impl Drop for Rc { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { unsafe { - let ptr = *self._ptr; + let ptr = *self.ptr; let thin = ptr as *const (); if thin as usize != mem::POST_DROP_USIZE { @@ -490,7 +488,7 @@ impl Clone for Rc { #[inline] fn clone(&self) -> Rc { self.inc_strong(); - Rc { _ptr: self._ptr } + Rc { ptr: self.ptr } } } @@ -691,7 +689,7 @@ impl fmt::Debug for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&*self._ptr, f) + fmt::Pointer::fmt(&*self.ptr, f) } } @@ -711,9 +709,7 @@ impl From for Rc { #[unsafe_no_drop_flag] #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { - // FIXME #12808: strange names to try to avoid interfering with - // field accesses of the contained type via Deref - _ptr: Shared>, + ptr: Shared>, } #[stable(feature = "rc_weak", since = "1.4.0")] @@ -749,7 +745,7 @@ impl Weak { None } else { self.inc_strong(); - Some(Rc { _ptr: self._ptr }) + Some(Rc { ptr: self.ptr }) } } } @@ -783,7 +779,7 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { unsafe { - let ptr = *self._ptr; + let ptr = *self.ptr; let thin = ptr as *const (); if thin as usize != mem::POST_DROP_USIZE { @@ -816,7 +812,7 @@ impl Clone for Weak { #[inline] fn clone(&self) -> Weak { self.inc_weak(); - Weak { _ptr: self._ptr } + Weak { ptr: self.ptr } } } @@ -848,7 +844,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - _ptr: Shared::new(Box::into_raw(box RcBox { + ptr: Shared::new(Box::into_raw(box RcBox { strong: Cell::new(0), weak: Cell::new(1), value: uninitialized(), @@ -910,8 +906,8 @@ impl RcBoxPtr for Rc { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); - &(**self._ptr) + assume(!(*(&self.ptr as *const _ as *const *const ())).is_null()); + &(**self.ptr) } } } @@ -924,8 +920,8 @@ impl RcBoxPtr for Weak { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); - &(**self._ptr) + assume(!(*(&self.ptr as *const _ as *const *const ())).is_null()); + &(**self.ptr) } } } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b2cbc29b1c74c..a1c7a293af0b3 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -390,8 +390,8 @@ impl RefCell { pub fn borrow(&self) -> Ref { match BorrowRef::new(&self.borrow) { Some(b) => Ref { - _value: unsafe { &*self.value.get() }, - _borrow: b, + value: unsafe { &*self.value.get() }, + borrow: b, }, None => panic!("RefCell already mutably borrowed"), } @@ -438,8 +438,8 @@ impl RefCell { pub fn borrow_mut(&self) -> RefMut { match BorrowRefMut::new(&self.borrow) { Some(b) => RefMut { - _value: unsafe { &mut *self.value.get() }, - _borrow: b, + value: unsafe { &mut *self.value.get() }, + borrow: b, }, None => panic!("RefCell already borrowed"), } @@ -491,7 +491,7 @@ impl PartialEq for RefCell { impl Eq for RefCell {} struct BorrowRef<'b> { - _borrow: &'b Cell, + borrow: &'b Cell, } impl<'b> BorrowRef<'b> { @@ -501,7 +501,7 @@ impl<'b> BorrowRef<'b> { WRITING => None, b => { borrow.set(b + 1); - Some(BorrowRef { _borrow: borrow }) + Some(BorrowRef { borrow: borrow }) }, } } @@ -510,9 +510,9 @@ impl<'b> BorrowRef<'b> { impl<'b> Drop for BorrowRef<'b> { #[inline] fn drop(&mut self) { - let borrow = self._borrow.get(); + let borrow = self.borrow.get(); debug_assert!(borrow != WRITING && borrow != UNUSED); - self._borrow.set(borrow - 1); + self.borrow.set(borrow - 1); } } @@ -521,10 +521,10 @@ impl<'b> Clone for BorrowRef<'b> { fn clone(&self) -> BorrowRef<'b> { // Since this Ref exists, we know the borrow flag // is not set to WRITING. - let borrow = self._borrow.get(); + let borrow = self.borrow.get(); debug_assert!(borrow != WRITING && borrow != UNUSED); - self._borrow.set(borrow + 1); - BorrowRef { _borrow: self._borrow } + self.borrow.set(borrow + 1); + BorrowRef { borrow: self.borrow } } } @@ -534,10 +534,8 @@ impl<'b> Clone for BorrowRef<'b> { /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct Ref<'b, T: ?Sized + 'b> { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _value: &'b T, - _borrow: BorrowRef<'b>, + value: &'b T, + borrow: BorrowRef<'b>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -546,7 +544,7 @@ impl<'b, T: ?Sized> Deref for Ref<'b, T> { #[inline] fn deref(&self) -> &T { - self._value + self.value } } @@ -565,8 +563,8 @@ impl<'b, T: ?Sized> Ref<'b, T> { #[inline] pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> { Ref { - _value: orig._value, - _borrow: orig._borrow.clone(), + value: orig.value, + borrow: orig.borrow.clone(), } } @@ -594,8 +592,8 @@ impl<'b, T: ?Sized> Ref<'b, T> { where F: FnOnce(&T) -> &U { Ref { - _value: f(orig._value), - _borrow: orig._borrow, + value: f(orig.value), + borrow: orig.borrow, } } @@ -627,9 +625,9 @@ impl<'b, T: ?Sized> Ref<'b, T> { pub fn filter_map(orig: Ref<'b, T>, f: F) -> Option> where F: FnOnce(&T) -> Option<&U> { - f(orig._value).map(move |new| Ref { - _value: new, - _borrow: orig._borrow, + f(orig.value).map(move |new| Ref { + value: new, + borrow: orig.borrow, }) } } @@ -667,8 +665,8 @@ impl<'b, T: ?Sized> RefMut<'b, T> { where F: FnOnce(&mut T) -> &mut U { RefMut { - _value: f(orig._value), - _borrow: orig._borrow, + value: f(orig.value), + borrow: orig.borrow, } } @@ -706,24 +704,24 @@ impl<'b, T: ?Sized> RefMut<'b, T> { pub fn filter_map(orig: RefMut<'b, T>, f: F) -> Option> where F: FnOnce(&mut T) -> Option<&mut U> { - let RefMut { _value, _borrow } = orig; - f(_value).map(move |new| RefMut { - _value: new, - _borrow: _borrow, + let RefMut { value, borrow } = orig; + f(value).map(move |new| RefMut { + value: new, + borrow: borrow, }) } } struct BorrowRefMut<'b> { - _borrow: &'b Cell, + borrow: &'b Cell, } impl<'b> Drop for BorrowRefMut<'b> { #[inline] fn drop(&mut self) { - let borrow = self._borrow.get(); + let borrow = self.borrow.get(); debug_assert!(borrow == WRITING); - self._borrow.set(UNUSED); + self.borrow.set(UNUSED); } } @@ -733,7 +731,7 @@ impl<'b> BorrowRefMut<'b> { match borrow.get() { UNUSED => { borrow.set(WRITING); - Some(BorrowRefMut { _borrow: borrow }) + Some(BorrowRefMut { borrow: borrow }) }, _ => None, } @@ -745,10 +743,8 @@ impl<'b> BorrowRefMut<'b> { /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct RefMut<'b, T: ?Sized + 'b> { - // FIXME #12808: strange name to try to avoid interfering with - // field accesses of the contained type via Deref - _value: &'b mut T, - _borrow: BorrowRefMut<'b>, + value: &'b mut T, + borrow: BorrowRefMut<'b>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -757,7 +753,7 @@ impl<'b, T: ?Sized> Deref for RefMut<'b, T> { #[inline] fn deref(&self) -> &T { - self._value + self.value } } @@ -765,7 +761,7 @@ impl<'b, T: ?Sized> Deref for RefMut<'b, T> { impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> { #[inline] fn deref_mut(&mut self) -> &mut T { - self._value + self.value } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index d2e98a795d935..483c3822df6ca 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -327,7 +327,7 @@ impl AtomicBool { /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this /// operation. The first describes the required ordering if the operation succeeds while the /// second describes the required ordering when the operation fails. The failure ordering can't - /// be `Acquire` or `AcqRel` and must be equivalent or weaker than the success ordering. + /// be `Release` or `AcqRel` and must be equivalent or weaker than the success ordering. /// /// # Examples /// @@ -376,7 +376,7 @@ impl AtomicBool { /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the operation /// succeeds while the second describes the required ordering when the operation fails. The - /// failure ordering can't be `Acquire` or `AcqRel` and must be equivalent or weaker than the + /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than the /// success ordering. /// /// # Examples @@ -663,7 +663,7 @@ impl AtomicIsize { /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this /// operation. The first describes the required ordering if the operation succeeds while the /// second describes the required ordering when the operation fails. The failure ordering can't - /// be `Acquire` or `AcqRel` and must be equivalent or weaker than the success ordering. + /// be `Release` or `AcqRel` and must be equivalent or weaker than the success ordering. /// /// # Examples /// @@ -705,7 +705,7 @@ impl AtomicIsize { /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the operation /// succeeds while the second describes the required ordering when the operation fails. The - /// failure ordering can't be `Acquire` or `AcqRel` and must be equivalent or weaker than the + /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than the /// success ordering. /// /// # Examples @@ -939,7 +939,7 @@ impl AtomicUsize { /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this /// operation. The first describes the required ordering if the operation succeeds while the /// second describes the required ordering when the operation fails. The failure ordering can't - /// be `Acquire` or `AcqRel` and must be equivalent or weaker than the success ordering. + /// be `Release` or `AcqRel` and must be equivalent or weaker than the success ordering. /// /// # Examples /// @@ -981,7 +981,7 @@ impl AtomicUsize { /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the operation /// succeeds while the second describes the required ordering when the operation fails. The - /// failure ordering can't be `Acquire` or `AcqRel` and must be equivalent or weaker than the + /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than the /// success ordering. /// /// # Examples @@ -1223,7 +1223,7 @@ impl AtomicPtr { /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this /// operation. The first describes the required ordering if the operation succeeds while the /// second describes the required ordering when the operation fails. The failure ordering can't - /// be `Acquire` or `AcqRel` and must be equivalent or weaker than the success ordering. + /// be `Release` or `AcqRel` and must be equivalent or weaker than the success ordering. /// /// # Examples /// @@ -1270,7 +1270,7 @@ impl AtomicPtr { /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory /// ordering of this operation. The first describes the required ordering if the operation /// succeeds while the second describes the required ordering when the operation fails. The - /// failure ordering can't be `Acquire` or `AcqRel` and must be equivalent or weaker than the + /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than the /// success ordering. /// /// # Examples @@ -1396,8 +1396,8 @@ unsafe fn atomic_compare_exchange(dst: *mut T, (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), - (_, Release) => panic!("there is no such thing as an acquire/release failure ordering"), - (_, AcqRel) => panic!("there is no such thing as a release failure ordering"), + (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), + (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), }; if ok { @@ -1446,8 +1446,8 @@ unsafe fn atomic_compare_exchange_weak(dst: *mut T, (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), - (_, Release) => panic!("there is no such thing as an acquire/release failure ordering"), - (_, AcqRel) => panic!("there is no such thing as a release failure ordering"), + (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), + (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), }; if ok { diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index d3146697ee627..7782a98a1d4e7 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -18,8 +18,9 @@ use middle::def_id::DefId; use infer; use traits::{self, ProjectionMode}; use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable}; +use ty::fast_reject::{self, SimplifiedType}; use syntax::ast::Name; -use util::nodemap::DefIdMap; +use util::nodemap::{DefIdMap, FnvHashMap}; /// A per-trait graph of impls in specialization order. At the moment, this /// graph forms a tree rooted with the trait itself, with all other nodes @@ -42,7 +43,124 @@ pub struct Graph { parent: DefIdMap, // the "root" impls are found by looking up the trait's def_id. - children: DefIdMap>, + children: DefIdMap, +} + +/// Children of a given impl, grouped into blanket/non-blanket varieties as is +/// done in `TraitDef`. +struct Children { + // Impls of a trait (or specializations of a given impl). To allow for + // quicker lookup, the impls are indexed by a simplified version of their + // `Self` type: impls with a simplifiable `Self` are stored in + // `nonblanket_impls` keyed by it, while all other impls are stored in + // `blanket_impls`. + // + // A similar division is used within `TraitDef`, but the lists there collect + // together *all* the impls for a trait, and are populated prior to building + // the specialization graph. + + /// Impls of the trait. + nonblanket_impls: FnvHashMap>, + + /// Blanket impls associated with the trait. + blanket_impls: Vec, +} + +/// The result of attempting to insert an impl into a group of children. +enum InsertResult<'a, 'tcx: 'a> { + /// The impl was inserted as a new child in this group of children. + BecameNewSibling, + + /// The impl replaced an existing impl that specializes it. + Replaced(DefId), + + /// The impl is a specialization of an existing child. + ShouldRecurseOn(DefId), + + /// The impl has an unresolvable overlap with an existing child (neither + /// specializes the other). + Overlapped(Overlap<'a, 'tcx>), +} + +impl Children { + fn new() -> Children { + Children { + nonblanket_impls: FnvHashMap(), + blanket_impls: vec![], + } + } + + /// Insert an impl into this set of children without comparing to any existing impls + fn insert_blindly(&mut self, tcx: &TyCtxt, impl_def_id: DefId) { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { + self.nonblanket_impls.entry(sty).or_insert(vec![]).push(impl_def_id) + } else { + self.blanket_impls.push(impl_def_id) + } + } + + /// Attempt to insert an impl into this set of children, while comparing for + /// specialiation relationships. + fn insert<'a, 'tcx>(&mut self, + tcx: &'a TyCtxt<'tcx>, + impl_def_id: DefId, + simplified_self: Option) + -> InsertResult<'a, 'tcx> + { + for slot in match simplified_self { + Some(sty) => self.filtered_mut(sty), + None => self.iter_mut(), + } { + let possible_sibling = *slot; + + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Topmost); + let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); + + if let Some(impl_header) = overlap { + let le = specializes(tcx, impl_def_id, possible_sibling); + let ge = specializes(tcx, possible_sibling, impl_def_id); + + if le && !ge { + debug!("descending as child of TraitRef {:?}", + tcx.impl_trait_ref(possible_sibling).unwrap()); + + // the impl specializes possible_sibling + return InsertResult::ShouldRecurseOn(possible_sibling); + } else if ge && !le { + debug!("placing as parent of TraitRef {:?}", + tcx.impl_trait_ref(possible_sibling).unwrap()); + + // possible_sibling specializes the impl + *slot = impl_def_id; + return InsertResult::Replaced(possible_sibling); + } else { + // overlap, but no specialization; error out + return InsertResult::Overlapped(Overlap { + with_impl: possible_sibling, + on_trait_ref: impl_header.trait_ref.unwrap(), + in_context: infcx, + }); + } + } + } + + // no overlap with any potential siblings, so add as a new sibling + debug!("placing as new sibling"); + self.insert_blindly(tcx, impl_def_id); + InsertResult::BecameNewSibling + } + + fn iter_mut<'a>(&'a mut self) -> Box + 'a> { + let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter_mut()); + Box::new(self.blanket_impls.iter_mut().chain(nonblanket)) + } + + fn filtered_mut<'a>(&'a mut self, sty: SimplifiedType) + -> Box + 'a> { + let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter_mut(); + Box::new(self.blanket_impls.iter_mut().chain(nonblanket)) + } } impl Graph { @@ -78,78 +196,53 @@ impl Graph { trait_ref, impl_def_id, trait_def_id); self.parent.insert(impl_def_id, trait_def_id); - self.children.entry(trait_def_id).or_insert(vec![]).push(impl_def_id); + self.children.entry(trait_def_id).or_insert(Children::new()) + .insert_blindly(tcx, impl_def_id); return Ok(()); } let mut parent = trait_def_id; + let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false); - // Ugly hack around borrowck limitations. Assigned only in the case - // where we bump downward an existing node in the graph. - let child_to_insert; - - 'descend: loop { - let mut possible_siblings = self.children.entry(parent).or_insert(vec![]); - - for slot in possible_siblings.iter_mut() { - let possible_sibling = *slot; - - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, ProjectionMode::Topmost); - let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); - - if let Some(impl_header) = overlap { - let le = specializes(tcx, impl_def_id, possible_sibling); - let ge = specializes(tcx, possible_sibling, impl_def_id); - - if le && !ge { - debug!("descending as child of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap()); - - // the impl specializes possible_sibling - parent = possible_sibling; - continue 'descend; - } else if ge && !le { - debug!("placing as parent of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap()); - - // possible_sibling specializes the impl - *slot = impl_def_id; - self.parent.insert(impl_def_id, parent); - self.parent.insert(possible_sibling, impl_def_id); - // we have to defer the insertion, because we can't - // relinquish the borrow of `self.children` - child_to_insert = possible_sibling; - break 'descend; - } else { - // overlap, but no specialization; error out - return Err(Overlap { - with_impl: possible_sibling, - on_trait_ref: impl_header.trait_ref.unwrap(), - in_context: infcx, - }); - } + // Descend the specialization tree, where `parent` is the current parent node + loop { + use self::InsertResult::*; + + let insert_result = self.children.entry(parent).or_insert(Children::new()) + .insert(tcx, impl_def_id, simplified); + + match insert_result { + BecameNewSibling => { + break; + } + Replaced(new_child) => { + self.parent.insert(new_child, impl_def_id); + let mut new_children = Children::new(); + new_children.insert_blindly(tcx, new_child); + self.children.insert(impl_def_id, new_children); + break; + } + ShouldRecurseOn(new_parent) => { + parent = new_parent; + } + Overlapped(error) => { + return Err(error); } } - - // no overlap with any potential siblings, so add as a new sibling - debug!("placing as new sibling"); - self.parent.insert(impl_def_id, parent); - possible_siblings.push(impl_def_id); - return Ok(()); } - self.children.insert(impl_def_id, vec![child_to_insert]); + self.parent.insert(impl_def_id, parent); Ok(()) } /// Insert cached metadata mapping from a child impl back to its parent. - pub fn record_impl_from_cstore(&mut self, parent: DefId, child: DefId) { + pub fn record_impl_from_cstore(&mut self, tcx: &TyCtxt, parent: DefId, child: DefId) { if self.parent.insert(child, parent).is_some() { bug!("When recording an impl from the crate store, information about its parent \ was already present."); } - self.children.entry(parent).or_insert(vec![]).push(child); + self.children.entry(parent).or_insert(Children::new()).insert_blindly(tcx, child); } /// The parent of a given impl, which is the def id of the trait when the diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 3ebf2ba4c849f..51f330686db6e 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -15,7 +15,7 @@ use ty; use ty::fast_reject; use ty::{Ty, TyCtxt, TraitRef}; use std::borrow::{Borrow}; -use std::cell::{Cell, Ref, RefCell}; +use std::cell::{Cell, RefCell}; use syntax::ast::Name; use rustc_front::hir; use util::nodemap::FnvHashMap; @@ -43,10 +43,17 @@ pub struct TraitDef<'tcx> { /// for resolving `X::Foo` type markers. pub associated_type_names: Vec, - // Impls of this trait. To allow for quicker lookup, the impls are indexed - // by a simplified version of their Self type: impls with a simplifiable - // Self are stored in nonblanket_impls keyed by it, while all other impls - // are stored in blanket_impls. + // Impls of a trait. To allow for quicker lookup, the impls are indexed by a + // simplified version of their `Self` type: impls with a simplifiable `Self` + // are stored in `nonblanket_impls` keyed by it, while all other impls are + // stored in `blanket_impls`. + // + // A similar division is used within `specialization_graph`, but the ones + // here are (1) stored as a flat list for the trait and (2) populated prior + // to -- and used while -- determining specialization order. + // + // FIXME: solve the reentrancy issues and remove these lists in favor of the + // ones in `specialization_graph`. // // These lists are tracked by `DepNode::TraitImpls`; we don't use // a DepTrackingMap but instead have the `TraitDef` insert the @@ -184,7 +191,7 @@ impl<'tcx> TraitDef<'tcx> { // if the impl is non-local, it's placed directly into the // specialization graph using parent information drawn from metadata. self.specialization_graph.borrow_mut() - .record_impl_from_cstore(parent_impl, impl_def_id) + .record_impl_from_cstore(tcx, parent_impl, impl_def_id) } } @@ -261,14 +268,6 @@ impl<'tcx> TraitDef<'tcx> { } } } - - pub fn borrow_impl_lists<'s>(&'s self, tcx: &TyCtxt<'tcx>) - -> (Ref<'s, Vec>, - Ref<'s, FnvHashMap>>) { - self.read_trait_impls(tcx); - (self.blanket_impls.borrow(), self.nonblanket_impls.borrow()) - } - } bitflags! { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 6edc26c70097a..73bed8dc56a85 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -80,6 +80,8 @@ pub struct ArgType { /// Only later will `original_ty` aka `%Foo` be used in the LLVM function /// pointer type, without ever having introspected it. pub ty: Type, + /// Signedness for integer types, None for other types + pub signedness: Option, /// Coerced LLVM Type pub cast: Option, /// Dummy argument, which is emitted before the real argument @@ -94,6 +96,7 @@ impl ArgType { kind: ArgKind::Direct, original_ty: original_ty, ty: ty, + signedness: None, cast: None, pad: None, attrs: llvm::Attributes::default() @@ -123,6 +126,19 @@ impl ArgType { self.kind = ArgKind::Ignore; } + pub fn extend_integer_width_to(&mut self, bits: u64) { + // Only integers have signedness + if let Some(signed) = self.signedness { + if self.ty.int_width() < bits { + self.attrs.set(if signed { + llvm::Attribute::SExt + } else { + llvm::Attribute::ZExt + }); + } + } + } + pub fn is_indirect(&self) -> bool { self.kind == ArgKind::Indirect } @@ -268,6 +284,9 @@ impl FnType { } else { let mut arg = ArgType::new(type_of::type_of(ccx, ty), type_of::sizing_type_of(ccx, ty)); + if ty.is_integral() { + arg.signedness = Some(ty.is_signed()); + } if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. diff --git a/src/librustc_trans/cabi_aarch64.rs b/src/librustc_trans/cabi_aarch64.rs index 4903af2a6ff7d..fc11e3888d3c2 100644 --- a/src/librustc_trans/cabi_aarch64.rs +++ b/src/librustc_trans/cabi_aarch64.rs @@ -163,6 +163,7 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(32); return; } if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { @@ -190,6 +191,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { if is_reg_ty(arg.ty) { + arg.extend_integer_width_to(32); return; } if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs index 35099399e317c..68a2e8aa8ce95 100644 --- a/src/librustc_trans/cabi_arm.rs +++ b/src/librustc_trans/cabi_arm.rs @@ -131,6 +131,7 @@ fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize { fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) { if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(32); return; } let size = ty_size(ret.ty, align_fn); @@ -150,6 +151,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) { fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) { if is_reg_ty(arg.ty) { + arg.extend_integer_width_to(32); return; } let align = align_fn(arg.ty); diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_trans/cabi_mips.rs index be9d4cad1db68..680310e195a41 100644 --- a/src/librustc_trans/cabi_mips.rs +++ b/src/librustc_trans/cabi_mips.rs @@ -86,6 +86,14 @@ fn ty_size(ty: Type) -> usize { } } +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(32); + } else { + ret.make_indirect(ccx); + } +} + fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { let orig_offset = *offset; let size = ty_size(arg.ty) * 8; @@ -98,6 +106,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { if !is_reg_ty(arg.ty) { arg.cast = Some(struct_ty(ccx, arg.ty)); arg.pad = padding_ty(ccx, align, orig_offset); + } else { + arg.extend_integer_width_to(32); } } @@ -146,8 +156,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { } pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { - if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) { - fty.ret.make_indirect(ccx); + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); } let mut offset = if fty.ret.is_indirect() { 4 } else { 0 }; diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs index d118cc86f2443..efbdce67a8b2a 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_trans/cabi_powerpc.rs @@ -82,6 +82,14 @@ fn ty_size(ty: Type) -> usize { } } +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(32); + } else { + ret.make_indirect(ccx); + } +} + fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { let orig_offset = *offset; let size = ty_size(arg.ty) * 8; @@ -94,6 +102,8 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { if !is_reg_ty(arg.ty) { arg.cast = Some(struct_ty(ccx, arg.ty)); arg.pad = padding_ty(ccx, align, orig_offset); + } else { + arg.extend_integer_width_to(32); } } @@ -141,8 +151,8 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { } pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { - if !fty.ret.is_ignore() && !is_reg_ty(fty.ret.ty) { - fty.ret.make_indirect(ccx); + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); } let mut offset = if fty.ret.is_indirect() { 4 } else { 0 }; diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_trans/cabi_powerpc64.rs index 7bc41d26f8b75..ba54e369fd838 100644 --- a/src/librustc_trans/cabi_powerpc64.rs +++ b/src/librustc_trans/cabi_powerpc64.rs @@ -153,6 +153,7 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(64); return; } @@ -187,6 +188,7 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { if is_reg_ty(arg.ty) { + arg.extend_integer_width_to(64); return; } diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index 415579eb221dd..b52231fa6b432 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -15,25 +15,29 @@ use super::common::*; use super::machine::*; pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { - if !fty.ret.is_ignore() && fty.ret.ty.kind() == Struct { - // Returning a structure. Most often, this will use - // a hidden first argument. On some platforms, though, - // small structs are returned as integers. - // - // Some links: - // http://www.angelcode.com/dev/callconv/callconv.html - // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp - let t = &ccx.sess().target.target; - if t.options.is_like_osx || t.options.is_like_windows { - match llsize_of_alloc(ccx, fty.ret.ty) { - 1 => fty.ret.cast = Some(Type::i8(ccx)), - 2 => fty.ret.cast = Some(Type::i16(ccx)), - 4 => fty.ret.cast = Some(Type::i32(ccx)), - 8 => fty.ret.cast = Some(Type::i64(ccx)), - _ => fty.ret.make_indirect(ccx) + if !fty.ret.is_ignore() { + if fty.ret.ty.kind() == Struct { + // Returning a structure. Most often, this will use + // a hidden first argument. On some platforms, though, + // small structs are returned as integers. + // + // Some links: + // http://www.angelcode.com/dev/callconv/callconv.html + // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp + let t = &ccx.sess().target.target; + if t.options.is_like_osx || t.options.is_like_windows { + match llsize_of_alloc(ccx, fty.ret.ty) { + 1 => fty.ret.cast = Some(Type::i8(ccx)), + 2 => fty.ret.cast = Some(Type::i16(ccx)), + 4 => fty.ret.cast = Some(Type::i32(ccx)), + 8 => fty.ret.cast = Some(Type::i64(ccx)), + _ => fty.ret.make_indirect(ccx) + } + } else { + fty.ret.make_indirect(ccx); } } else { - fty.ret.make_indirect(ccx); + fty.ret.extend_integer_width_to(32); } } @@ -42,6 +46,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { if arg.ty.kind() == Struct { arg.make_indirect(ccx); arg.attrs.set(Attribute::ByVal); + } else { + arg.extend_integer_width_to(32); } } } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index e9e9e266c7786..805c7d345a0e7 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -400,6 +400,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { } else { arg.cast = Some(llreg_ty(ccx, &cls)); } + } else { + arg.extend_integer_width_to(32); } } diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs index a5077f68fb58c..71ecb6e9ca104 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_trans/cabi_x86_win64.rs @@ -26,6 +26,8 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { 8 => a.cast = Some(Type::i64(ccx)), _ => a.make_indirect(ccx) } + } else { + a.extend_integer_width_to(32); } }; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4c29023660a68..234042ab011bc 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -428,10 +428,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, mut val: V) -> &'a mut V { let starting_index = bucket.index(); - let size = { - let table = bucket.table(); // FIXME "lifetime too short". - table.size() - }; + let size = bucket.table().size(); // Save the *starting point*. let mut bucket = bucket.stash(); // There can be at most `size - dib` buckets to displace, because @@ -744,10 +741,9 @@ impl HashMap let h = bucket.hash(); let (b, k, v) = bucket.take(); self.insert_hashed_ordered(h, k, v); - { - let t = b.table(); // FIXME "lifetime too short". - if t.size() == 0 { break } - }; + if b.table().size() == 0 { + break; + } b.into_bucket() } Empty(b) => b.into_bucket() diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 40f6528f63efb..22ec3e0ac57bc 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -617,7 +617,7 @@ pub mod consts { #[stable(feature = "env", since = "1.0.0")] pub const ARCH: &'static str = super::arch::ARCH; - /// The family of the operating system. In this case, `unix`. + /// The family of the operating system. Example value is `unix`. /// /// Some possible values: /// @@ -626,8 +626,8 @@ pub mod consts { #[stable(feature = "env", since = "1.0.0")] pub const FAMILY: &'static str = super::os::FAMILY; - /// A string describing the specific operating system in use: in this - /// case, `linux`. + /// A string describing the specific operating system in use. + /// Example value is `linux`. /// /// Some possible values: /// @@ -646,7 +646,7 @@ pub mod consts { pub const OS: &'static str = super::os::OS; /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. + /// platform. Example value is `lib`. /// /// Some possible values: /// @@ -656,7 +656,7 @@ pub mod consts { pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX; /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. + /// platform. Example value is `.so`. /// /// Some possible values: /// @@ -667,7 +667,7 @@ pub mod consts { pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX; /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. + /// platform that goes after the dot. Example value is `so`. /// /// Some possible values: /// @@ -678,7 +678,7 @@ pub mod consts { pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION; /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. + /// platform. Example value is `.exe`. /// /// Some possible values: /// @@ -690,7 +690,7 @@ pub mod consts { pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX; /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. + /// on this platform. Example value is `exe`. /// /// Some possible values: /// diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c index 00bfa63e6fea8..d2ebdcca80cf0 100644 --- a/src/rt/rust_test_helpers.c +++ b/src/rt/rust_test_helpers.c @@ -243,3 +243,7 @@ double rust_interesting_average(uint64_t n, ...) { va_end(pairs); return sum / n; } + +int32_t rust_int8_to_int32(int8_t x) { + return (int32_t)x; +} diff --git a/src/test/run-pass/cabi-int-widening.rs b/src/test/run-pass/cabi-int-widening.rs new file mode 100644 index 0000000000000..c7a2275933335 --- /dev/null +++ b/src/test/run-pass/cabi-int-widening.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[link(name = "rust_test_helpers")] +extern { + fn rust_int8_to_int32(_: i8) -> i32; +} + +fn main() { + let x = unsafe { + rust_int8_to_int32(-1) + }; + + assert!(x == -1); +}